mirror of
https://github.com/xhongc/music-tag-web.git
synced 2026-02-02 17:59:07 +08:00
feature:a
This commit is contained in:
1686
.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a.xml
generated
1686
.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a.xml
generated
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
40
applications/flow/migrations/0002_nodetemplate.py
Normal file
40
applications/flow/migrations/0002_nodetemplate.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Generated by Django 2.2.6 on 2022-02-10 14:21
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_mysql.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('flow', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NodeTemplate',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, verbose_name='节点名称')),
|
||||
('uuid', models.CharField(max_length=255, unique=True, verbose_name='UUID')),
|
||||
('description', models.CharField(blank=True, max_length=255, null=True, verbose_name='节点描述')),
|
||||
('show', models.BooleanField(default=True, verbose_name='是否显示')),
|
||||
('top', models.IntegerField(default=300)),
|
||||
('left', models.IntegerField(default=300)),
|
||||
('ico', models.CharField(blank=True, max_length=64, null=True, verbose_name='icon')),
|
||||
('fail_retry_count', models.IntegerField(default=0, verbose_name='失败重试次数')),
|
||||
('fail_offset', models.IntegerField(default=0, verbose_name='失败重试间隔')),
|
||||
('fail_offset_unit', models.CharField(choices=[('seconds', '秒'), ('hours', '时'), ('minutes', '分')], max_length=32, verbose_name='重试间隔单位')),
|
||||
('node_type', models.IntegerField(default=2)),
|
||||
('component_code', models.CharField(max_length=255, verbose_name='插件名称')),
|
||||
('is_skip_fail', models.BooleanField(default=False, verbose_name='忽略失败')),
|
||||
('is_timeout_alarm', models.BooleanField(default=False, verbose_name='超时告警')),
|
||||
('inputs', django_mysql.models.JSONField(default=dict, verbose_name='输入参数')),
|
||||
('outputs', django_mysql.models.JSONField(default=dict, verbose_name='输出参数')),
|
||||
('template_type', models.CharField(default='2', max_length=1, verbose_name='节点模板类型')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
28
applications/flow/migrations/0003_auto_20220210_1737.py
Normal file
28
applications/flow/migrations/0003_auto_20220210_1737.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 2.2.6 on 2022-02-10 17:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('flow', '0002_nodetemplate'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='node',
|
||||
name='content',
|
||||
field=models.IntegerField(default=0, verbose_name='模板id'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='noderun',
|
||||
name='content',
|
||||
field=models.IntegerField(default=0, verbose_name='模板id'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='nodetemplate',
|
||||
name='content',
|
||||
field=models.IntegerField(default=0, verbose_name='模板id'),
|
||||
),
|
||||
]
|
||||
@@ -59,6 +59,8 @@ class BaseNode(models.Model):
|
||||
|
||||
inputs = JSONField("输入参数", default=dict)
|
||||
outputs = JSONField("输出参数", default=dict)
|
||||
# 如为子流程content为process id, 如为 节点模板为node id
|
||||
content = models.IntegerField("模板id", default=0)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -96,3 +98,7 @@ class NodeRun(BaseNode):
|
||||
@staticmethod
|
||||
def field_names():
|
||||
return [field.name for field in NodeRun._meta.get_fields() if field.name not in ["id"]]
|
||||
|
||||
|
||||
class NodeTemplate(BaseNode):
|
||||
template_type = models.CharField("节点模板类型", max_length=1, default="2")
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import json
|
||||
|
||||
from django.db import transaction
|
||||
from rest_framework import serializers
|
||||
from bamboo_engine import api
|
||||
from django.db import transaction
|
||||
from pipeline.eri.runtime import BambooDjangoRuntime
|
||||
from rest_framework import serializers
|
||||
|
||||
from applications.flow.constants import PIPELINE_STATE_TO_FLOW_STATE
|
||||
from applications.flow.models import Process, Node, ProcessRun, NodeRun
|
||||
from applications.flow.models import Process, Node, ProcessRun, NodeRun, NodeTemplate
|
||||
from applications.utils.uuid_helper import get_uuid
|
||||
|
||||
|
||||
class ProcessViewSetsSerializer(serializers.Serializer):
|
||||
@@ -17,16 +18,22 @@ class ProcessViewSetsSerializer(serializers.Serializer):
|
||||
pipeline_tree = serializers.JSONField(required=True)
|
||||
|
||||
def save(self, **kwargs):
|
||||
if self.instance is not None:
|
||||
self.update(instance=self.instance, validated_data=self.validated_data)
|
||||
else:
|
||||
self.create(validated_data=self.validated_data)
|
||||
|
||||
def create(self, validated_data):
|
||||
node_map = {}
|
||||
for node in self.validated_data["pipeline_tree"]["nodes"]:
|
||||
for node in validated_data["pipeline_tree"]["nodes"]:
|
||||
node_map[node["uuid"]] = node
|
||||
dag = {k: [] for k in node_map.keys()}
|
||||
for line in self.validated_data["pipeline_tree"]["lines"]:
|
||||
dag[line["from"]].append(line["to"])
|
||||
with transaction.atomic():
|
||||
process = Process.objects.create(name=self.validated_data["name"],
|
||||
description=self.validated_data["description"],
|
||||
run_type=self.validated_data["run_type"],
|
||||
process = Process.objects.create(name=validated_data["name"],
|
||||
description=validated_data["description"],
|
||||
run_type=validated_data["run_type"],
|
||||
dag=dag)
|
||||
bulk_nodes = []
|
||||
for node in node_map.values():
|
||||
@@ -38,7 +45,7 @@ class ProcessViewSetsSerializer(serializers.Serializer):
|
||||
fail_retry_count=node_data.get("fail_retry_count", 0) or 0,
|
||||
fail_offset=node_data.get("fail_offset", 0) or 0,
|
||||
fail_offset_unit=node_data.get("fail_offset_unit", "seconds"),
|
||||
node_type=node.get("type", 3),
|
||||
node_type=node.get("type", 2),
|
||||
is_skip_fail=node_data["is_skip_fail"],
|
||||
is_timeout_alarm=node_data["is_skip_fail"],
|
||||
inputs=node_data["inputs"],
|
||||
@@ -47,9 +54,53 @@ class ProcessViewSetsSerializer(serializers.Serializer):
|
||||
left=node["left"],
|
||||
ico=node["ico"],
|
||||
outputs={},
|
||||
component_code="http_request"
|
||||
component_code="http_request",
|
||||
content=node.get("content", 0) or 0
|
||||
))
|
||||
Node.objects.bulk_create(bulk_nodes, batch_size=500)
|
||||
self._data = {}
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
node_map = {}
|
||||
for node in validated_data["pipeline_tree"]["nodes"]:
|
||||
node_map[node["uuid"]] = node
|
||||
dag = {k: [] for k in node_map.keys()}
|
||||
for line in self.validated_data["pipeline_tree"]["lines"]:
|
||||
dag[line["from"]].append(line["to"])
|
||||
with transaction.atomic():
|
||||
instance.name = validated_data["name"]
|
||||
instance.description = validated_data["description"]
|
||||
instance.run_type = validated_data["run_type"]
|
||||
instance.dag = dag
|
||||
instance.save()
|
||||
bulk_nodes = []
|
||||
node_dict = Node.objects.filter(process_id=instance.id).in_bulk(field_name="uuid")
|
||||
for node in node_map.values():
|
||||
node_data = node["node_data"]
|
||||
node_obj = node_dict[node["uuid"]]
|
||||
|
||||
node_obj.content = node.get("content", 0) or 0
|
||||
node_obj.name = node_data["node_name"]
|
||||
node_obj.description = node_data["description"]
|
||||
node_obj.fail_retry_count = node_data.get("fail_retry_count", 0) or 0
|
||||
node_obj.fail_offset = node_data.get("fail_offset", 0) or 0
|
||||
node_obj.fail_offset_unit = node_data.get("fail_offset_unit", "seconds")
|
||||
node_obj.node_type = node.get("type", 3)
|
||||
node_obj.is_skip_fail = node_data["is_skip_fail"]
|
||||
node_obj.is_timeout_alarm = node_data["is_timeout_alarm"]
|
||||
node_obj.inputs = node_data["inputs"]
|
||||
node_obj.show = node["show"]
|
||||
node_obj.top = node["top"]
|
||||
node_obj.left = node["left"]
|
||||
node_obj.ico = node["ico"]
|
||||
node_obj.outputs = {}
|
||||
node_obj.component_code = "http_request"
|
||||
bulk_nodes.append(node_obj)
|
||||
Node.objects.bulk_update(bulk_nodes, fields=["name", "description", "fail_retry_count", "fail_offset",
|
||||
"fail_offset_unit", "node_type", "is_skip_fail",
|
||||
"is_timeout_alarm", "inputs", "show", "top", "left", "ico",
|
||||
"outputs", "component_code"], batch_size=500)
|
||||
self._data = {}
|
||||
|
||||
|
||||
class ListProcessViewSetsSerializer(serializers.ModelSerializer):
|
||||
@@ -89,6 +140,7 @@ class RetrieveProcessViewSetsSerializer(serializers.ModelSerializer):
|
||||
"ico": node["ico"],
|
||||
"type": node["node_type"],
|
||||
"name": node["name"],
|
||||
"content": node["content"],
|
||||
"node_data": {
|
||||
"inputs": node["inputs"],
|
||||
"run_mark": 0,
|
||||
@@ -159,3 +211,14 @@ class RetrieveProcessRunViewSetsSerializer(serializers.ModelSerializer):
|
||||
|
||||
class ExecuteProcessSerializer(serializers.Serializer):
|
||||
process_id = serializers.IntegerField(required=True)
|
||||
|
||||
|
||||
class NodeTemplateSerializer(serializers.ModelSerializer):
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs["uuid"] = get_uuid()
|
||||
return attrs
|
||||
|
||||
class Meta:
|
||||
model = NodeTemplate
|
||||
exclude = ("uuid",)
|
||||
|
||||
@@ -5,3 +5,6 @@ from . import views
|
||||
flow_router = DefaultRouter()
|
||||
flow_router.register(r"flow", viewset=views.ProcessViewSets, base_name="flow")
|
||||
flow_router.register(r"run", viewset=views.ProcessRunViewSets, base_name="run")
|
||||
|
||||
node_router = DefaultRouter()
|
||||
node_router.register(r"template", viewset=views.NodeTemplateViewSet, base_name="template")
|
||||
|
||||
@@ -6,10 +6,10 @@ from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from applications.flow.models import Process, Node, ProcessRun, NodeRun
|
||||
from applications.flow.models import Process, Node, ProcessRun, NodeRun, NodeTemplate
|
||||
from applications.flow.serializers import ProcessViewSetsSerializer, ListProcessViewSetsSerializer, \
|
||||
RetrieveProcessViewSetsSerializer, ExecuteProcessSerializer, ListProcessRunViewSetsSerializer, \
|
||||
RetrieveProcessRunViewSetsSerializer
|
||||
RetrieveProcessRunViewSetsSerializer, NodeTemplateSerializer
|
||||
from applications.utils.dag_helper import DAG, instance_dag
|
||||
from component.drf.viewsets import GenericViewSet
|
||||
|
||||
@@ -18,6 +18,7 @@ class ProcessViewSets(mixins.ListModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
GenericViewSet):
|
||||
queryset = Process.objects.order_by("-update_time")
|
||||
|
||||
@@ -85,6 +86,15 @@ class ProcessRunViewSets(mixins.ListModelMixin,
|
||||
return ExecuteProcessSerializer
|
||||
|
||||
|
||||
class NodeTemplateViewSet(mixins.ListModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
GenericViewSet):
|
||||
queryset = NodeTemplate.objects.order_by("-id")
|
||||
serializer_class = NodeTemplateSerializer
|
||||
|
||||
|
||||
# Create your views here.
|
||||
def flow(request):
|
||||
# 使用 builder 构造出流程描述结构
|
||||
|
||||
5
applications/utils/uuid_helper.py
Normal file
5
applications/utils/uuid_helper.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import uuid
|
||||
|
||||
|
||||
def get_uuid():
|
||||
return str(uuid.uuid4()).replace("-", "")
|
||||
@@ -1,2 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
true = True
|
||||
false = False
|
||||
a = {"result": true, "code": "OK", "message": "success", "data": {"menu": [
|
||||
{"name": "home", "cnName": "首页", "to": "/home", "icon": "iconfont icon-mianxingtubiao-shouye", "hasChild": false,
|
||||
"children": []},
|
||||
{"name": "AgentList", "cnName": "Agent管理", "to": "/agentlist", "icon": "iconfont icon-mianxingtubiao-Agentguanli",
|
||||
"hasChild": true, "children": [{"name": "AgentList", "cnName": "Agent列表", "to": "/agentlist", "hasChild": false},
|
||||
{"name": "AgentMonitor", "cnName": "Agent监视", "to": "/agentmonitor",
|
||||
"hasChild": false}]},
|
||||
{"name": "NewJob", "cnName": "作业管理", "to": "/newjob", "icon": "iconfont icon-mianxingtubiao-zuoyeguanli",
|
||||
"hasChild": true, "children": [{"name": "NewJob", "cnName": "新建作业", "to": "/newjob", "hasChild": false},
|
||||
{"name": "JobList", "cnName": "作业列表", "to": "/joblist", "hasChild": false}]},
|
||||
{"name": "NewJobFlow", "cnName": "作业流管理", "to": "/newjobflow",
|
||||
"icon": "iconfont icon-mianxingtubiao-zuoyeliuguanli", "hasChild": true,
|
||||
"children": [{"name": "NewJobFlow", "cnName": "新建作业流", "to": "/newjobflow", "hasChild": false},
|
||||
{"name": "JobFlowList", "cnName": "作业流列表", "to": "/jobflowlist", "hasChild": false},
|
||||
{"name": "CalendarMgmt", "cnName": "日历管理", "to": "/calendarmgmt", "hasChild": false},
|
||||
{"name": "VariableMgmt", "cnName": "变量管理", "to": "/variablemgmt", "hasChild": false}]},
|
||||
{"name": "JobMonitor", "cnName": "作业监视", "to": "/jobmonitor", "icon": "iconfont icon-mianxingtubiao-zuoyejiankong",
|
||||
"hasChild": false}, {"name": "LargeScreen", "cnName": "作业监视大屏", "to": "/largescreen",
|
||||
"icon": "iconfont icon-mianxingtubiao-zuoyejiankongdaping", "hasChild": false},
|
||||
{"name": "Report", "cnName": "报表分析", "to": "/report", "icon": "iconfont icon-xianxingtubiao-shengchengbaobiao",
|
||||
"hasChild": false},
|
||||
{"name": "JobHistory", "cnName": "作业历史", "to": "/jobhistory", "icon": "iconfont icon-mianxingtubiao-zuoyelishi",
|
||||
"hasChild": false},
|
||||
{"name": "AlarmList", "cnName": "告警中心", "to": "/alarmlist", "icon": "iconfont icon-mianxingtubiao-gaojingzhongxin",
|
||||
"hasChild": false, "children": []},
|
||||
{"name": "SysSetup", "cnName": "系统管理", "to": "/syssetup", "icon": "iconfont icon-mianxingtubiao-shezhi",
|
||||
"hasChild": true, "children": [{"name": "SysSetup", "cnName": "系统设置", "to": "/syssetup", "hasChild": false},
|
||||
{"name": "UserAndPermissions", "cnName": "用户与权限", "to": "/userandpermissions",
|
||||
"hasChild": false},
|
||||
{"name": "SystemClassManage", "cnName": "系统类别管理", "to": "/systemclassmanage",
|
||||
"hasChild": false},
|
||||
{"name": "Log", "cnName": "操作审计", "to": "/log", "hasChild": false}]}], "router": [
|
||||
{"path": "/", "name": "home", "component": "Home", "meta": {"title": "首页"}},
|
||||
{"path": "/log", "name": "Log", "component": "Log", "meta": {"title": "操作审计"}},
|
||||
{"path": "/addcalendarmgmt", "name": "AddCalendarMgmt", "component": "AddCalendarMgmt",
|
||||
"meta": {"title": "操作日历", "back": "true", "fatherName": "CalendarMgmt"}},
|
||||
{"path": "/variablechange", "name": "variableChange", "component": "variableChange",
|
||||
"meta": {"title": "变量表", "back": "true", "fatherName": "VariableMgmt"}},
|
||||
{"path": "/singlejob", "name": "SingleJob", "component": "SingleJob",
|
||||
"meta": {"title": "单个作业", "back": "true", "fatherName": "NewJob"}},
|
||||
{"path": "/singleJobdetail", "name": "singleJobDetail", "component": "SingleJob",
|
||||
"meta": {"title": "作业管理 > 修改作业 > 单个作业"}}, {"path": "/viewdetail", "name": "ViewDetail", "component": "ViewDetail",
|
||||
"meta": {"title": "作业流视图详情", "back": "true",
|
||||
"fatherName": "JobMonitor"}},
|
||||
{"path": "/jobflowdetail", "name": "JobFlowDetail", "component": "JobFlowDetail",
|
||||
"meta": {"title": "作业流视图历史详情", "back": "true", "fatherName": "JobHistory"}},
|
||||
{"path": "/jobviewdetail", "name": "JobViewDetail", "component": "JobViewDetail",
|
||||
"meta": {"title": "作业视图历史详情", "back": "true", "fatherName": "JobHistory"}},
|
||||
{"path": "/multiplejob", "name": "MultipleJob", "component": "MultipleJob",
|
||||
"meta": {"title": "批量作业导入", "back": "true", "fatherName": "NewJob"}},
|
||||
{"path": "/scanfile", "name": "ScanFile", "component": "ScanFile",
|
||||
"meta": {"title": "导入详情", "back": "true", "fatherName": "NewJob"}},
|
||||
{"path": "/home", "name": "home", "component": "Home", "meta": {"title": "首页"}},
|
||||
{"path": "/agentlist", "name": "AgentList", "component": "AgentList", "meta": {"title": "Agent列表"}},
|
||||
{"path": "/agentmonitor", "name": "AgentMonitor", "component": "AgentMonitor", "meta": {"title": "Agent监视"}},
|
||||
{"path": "/calendarmgmt", "name": "CalendarMgmt", "component": "CalendarMgmt", "meta": {"title": "日历管理"}},
|
||||
{"path": "/jobflowlist", "name": "JobFlowList", "component": "JobFlowList", "meta": {"title": "作业流列表"}},
|
||||
{"path": "/newjobflow", "name": "NewJobFlow", "component": "NewJobFlow", "meta": {"title": "新建作业流"}},
|
||||
{"path": "/singlejobflow", "name": "SingleJobFlow", "component": "SingleJobFlow",
|
||||
"meta": {"title": "单个作业流", "back": "true", "fatherName": "NewJobFlow"}},
|
||||
{"path": "/multiplejobflow", "name": "MultipleJobFlow", "component": "MultipleJobFlow",
|
||||
"meta": {"title": "批量导入", "back": "true", "fatherName": "NewJobFlow"}},
|
||||
{"path": "/importfile", "name": "importFile", "component": "ImportFile",
|
||||
"meta": {"title": "导入详情", "back": "true", "fatherName": "NewJobFlow"}},
|
||||
{"path": "/variablemgmt", "name": "VariableMgmt", "component": "VariableMgmt", "meta": {"title": "变量管理"}},
|
||||
{"path": "/joblist", "name": "JobList", "component": "JobList", "meta": {"title": "作业列表"}},
|
||||
{"path": "/newjob", "name": "NewJob", "component": "NewJob", "meta": {"title": "新建作业"}},
|
||||
{"path": "/jobhistory", "name": "JobHistory", "component": "JobHistory", "meta": {"title": "作业历史"}, "children": [
|
||||
{"path": "/jobflowviewhistory", "name": "JobFlowViewHistory", "component": "JobFlowViewHistory",
|
||||
"meta": {"title": "作业历史", "fatherName": "JobHistory"}},
|
||||
{"path": "/jobviewhistory", "name": "JobViewHistory", "component": "JobViewHistory",
|
||||
"meta": {"title": "作业历史", "fatherName": "JobHistory"}}]},
|
||||
{"path": "/report", "name": "Report", "component": "Report", "meta": {"title": "报表分析"}},
|
||||
{"path": "/largescreen", "name": "LargeScreen", "component": "LargeScreen", "meta": {"title": "作业监视大屏"}},
|
||||
{"path": "/jobmonitor", "name": "JobMonitor", "component": "JobMonitor", "meta": {"title": "作业监视"}, "children": [
|
||||
{"path": "/jobview", "name": "JobView", "component": "JobView",
|
||||
"meta": {"title": "作业监视", "fatherName": "JobMonitor"}},
|
||||
{"path": "/jobflowview", "name": "JobFlowView", "component": "JobFlowView",
|
||||
"meta": {"title": "作业监视", "fatherName": "JobMonitor"}}]},
|
||||
{"path": "/jobdetail", "name": "jobDetail", "component": "JobDetail",
|
||||
"meta": {"title": "作业视图详情", "back": "true", "fatherName": "JobMonitor"}},
|
||||
{"path": "/syssetup", "name": "SysSetup", "component": "SysSetup", "meta": {"title": "系统设置"}},
|
||||
{"path": "/userandpermissions", "name": "UserAndPermissions", "component": "UserAndPermissions",
|
||||
"meta": {"title": "用户与权限"}},
|
||||
{"path": "/systemclassmanage", "name": "SystemClassManage", "component": "SystemClassManage",
|
||||
"meta": {"title": "系统类别管理"}},
|
||||
{"path": "/logmange", "name": "LogMange", "component": "LogMange", "meta": {"title": "日志管理"}},
|
||||
{"path": "/alarmlist", "name": "AlarmList", "component": "AlarmList", "meta": {"title": "告警中心"}}], "permission": [
|
||||
{"url": "/agentlist", "auth": {"search": true, "create": true, "modify": true, "del": true}},
|
||||
{"url": "/agentmonitor", "auth": {"search": true}}, {"url": "/newjob", "auth": {"create": true}},
|
||||
{"url": "/joblist", "auth": {"search": true, "operate": true, "modify": true, "del": true}},
|
||||
{"url": "/newjobflow", "auth": {"create": true}},
|
||||
{"url": "/jobflowlist", "auth": {"search": true, "operate": true, "modify": true, "del": true}},
|
||||
{"url": "/calendarmgmt", "auth": {"search": true, "create": true, "modify": true, "del": true}},
|
||||
{"url": "/variablemgmt", "auth": {"search": true, "create": true, "modify": true, "del": true}},
|
||||
{"url": "/jobflowview", "auth": {"search": true, "operate": true}},
|
||||
{"url": "/jobflowviewhistory", "auth": {"search": true}},
|
||||
{"url": "/jobview", "auth": {"search": true, "operate": true}},
|
||||
{"url": "/jobviewhistory", "auth": {"search": true}}, {"url": "/alarmlist", "auth": {"search": true}},
|
||||
{"url": "/syssetup", "auth": {"operate": true, "modify": true}},
|
||||
{"url": "/userandpermissions", "auth": {"search": true, "create": true}},
|
||||
{"url": "/systemclassmanage", "auth": {"search": true, "create": true, "modify": true, "del": true}},
|
||||
{"url": "/log", "auth": {"search": true}}, {"url": "/viewdetail", "auth": {"search": true, "operate": true}}]}}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,10 +15,11 @@ Including another URLconf
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from applications.flow.urls import flow_router
|
||||
from applications.flow.urls import flow_router, node_router
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path("process/", include(flow_router.urls)),
|
||||
path("node/", include(node_router.urls)),
|
||||
|
||||
]
|
||||
|
||||
@@ -3,22 +3,22 @@ import {GET, POST, PUT, DELETE, reUrl} from '../../axiosconfig/axiosconfig'
|
||||
export default {
|
||||
// 作业台
|
||||
list: function(params) {
|
||||
return GET(reUrl + '/content/', params)
|
||||
return GET(reUrl + '/node/template/', params)
|
||||
},
|
||||
create: function(params) {
|
||||
return POST(reUrl + '/content/', params)
|
||||
return POST(reUrl + '/node/template/', params)
|
||||
},
|
||||
retrieve: function(id, params) {
|
||||
return GET(reUrl + '/content/' + JSON.stringify(id) + '/', params)
|
||||
return GET(reUrl + '/node/template/' + JSON.stringify(id) + '/', params)
|
||||
},
|
||||
update: function(id, params) {
|
||||
return PUT(reUrl + '/content/' + JSON.stringify(id) + '/', params)
|
||||
return PUT(reUrl + '/node/template/' + JSON.stringify(id) + '/', params)
|
||||
},
|
||||
clone: function(params) {
|
||||
return POST(reUrl + '/content/clone/', params)
|
||||
return POST(reUrl + '/node/template/clone/', params)
|
||||
},
|
||||
delete: function(id) {
|
||||
return DELETE(reUrl + '/content/' + JSON.stringify(id) + '/')
|
||||
return DELETE(reUrl + '/node/template/' + JSON.stringify(id) + '/')
|
||||
},
|
||||
execute: function(params) {
|
||||
return POST(reUrl + '/content/execute/', params)
|
||||
|
||||
@@ -32,6 +32,16 @@ export default {
|
||||
"hasChild": false,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"name": "NewJob",
|
||||
"cnName": "作业节点管理",
|
||||
"to": "/newjob",
|
||||
"icon": "iconfont icon-mianxingtubiao-zuoyeguanli",
|
||||
"hasChild": true,
|
||||
"children": [
|
||||
{"name": "NewJob", "cnName": "新建作业", "to": "/newjob", "hasChild": false},
|
||||
{"name": "JobList", "cnName": "作业列表", "to": "/joblist", "hasChild": false}]
|
||||
},
|
||||
{
|
||||
'name': 'NewJobFlow',
|
||||
'cnName': '作业流管理',
|
||||
|
||||
@@ -24,7 +24,7 @@ export default G6 => {
|
||||
return
|
||||
}
|
||||
//开始节点,结束节点, 作业流节点不做处理
|
||||
if (model.nodeType === 0 || model.nodeType === 1 || model.nodeType === 3) {
|
||||
if (model.nodeType === 0 || model.nodeType === 1) {
|
||||
return
|
||||
}
|
||||
//先将所有当前是 click 状态的节点/edge 置为非 selected 状态
|
||||
|
||||
@@ -28,6 +28,29 @@
|
||||
:control-type="controlType" @empty-task-make="handleEmptyTaskMake"></task-make>
|
||||
</Drawer>
|
||||
</div>
|
||||
<bk-dialog title="连线模式选择"
|
||||
v-model="flowModeDialog.show"
|
||||
:confirm-fn="handleFlowAddEdgeConfirm"
|
||||
ext-cls="add-mode-dialog"
|
||||
:mask-close="false"
|
||||
header-position="left">
|
||||
<add-mode-dialog :key="flowModeDialogKey" ref="addModeDialog"></add-mode-dialog>
|
||||
<bk-dialog v-model="flowModeDialog.childDialog.show"
|
||||
:mask-close="false"
|
||||
:width="flowModeDialog.childDialog.width"
|
||||
header-position="left"
|
||||
:render-directive="'if'"
|
||||
:position="{ top: 50 }"
|
||||
ext-cls="pre-flow-canvas-dialog"
|
||||
:confirm-fn="handlePreFlowNOdeAddConfirm"
|
||||
:show-footer="flowModeDialog.childDialog.footerShow">
|
||||
<div slot="header">
|
||||
<span style="color: #313237;">当前作业流:{{flowModeDialog.childDialog.title}}</span>
|
||||
<span class="iconfont icon-mianxingtubiao-wenti" style="margin-left: 4px;color: #979BA5;font-size: 16px;" v-bk-tooltips="flowModeTipConfig"></span>
|
||||
</div>
|
||||
<pre-flow-canvas :options="flowModeDialog.curObj" :pre-edges="flowModeDialog.preEdges" ref="preFlowCanvas"></pre-flow-canvas>
|
||||
</bk-dialog>
|
||||
</bk-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -36,6 +59,8 @@
|
||||
import {
|
||||
deepClone, getUUID
|
||||
} from '../../common/util.js'
|
||||
import addModeDialog from './single_job_flow/addModeDialog.vue'
|
||||
import preFlowCanvas from './single_job_flow/preFlowCanvas.vue'
|
||||
import nodeInfo from './single_job_flow/nodeInfo.vue'
|
||||
import edgeInfo from './single_job_flow/edgeInfo.vue'
|
||||
import headerPanel from './single_job_flow/headerPanel.vue'
|
||||
@@ -50,7 +75,9 @@
|
||||
taskMake, // 任务编排
|
||||
headerPanel, // 头部菜单
|
||||
nodeInfo, // 节点信息
|
||||
edgeInfo // 分支线信息
|
||||
edgeInfo, // 分支线信息
|
||||
addModeDialog, // 前置作业流连线模式选择弹窗
|
||||
preFlowCanvas // 前置作业流详情画布
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
@@ -62,6 +89,13 @@
|
||||
checkFlag: true,
|
||||
dragStartNode: {},
|
||||
jobFlowFrom: null,
|
||||
flowModeTipConfig: {
|
||||
content: '选择前置作业流中的某个节点作为前置依赖连线,不可重复选择节点连线,不可选择该作业流中的前置作业流节点!',
|
||||
placement: 'right',
|
||||
width: 300,
|
||||
zIndex: 999999
|
||||
// delay: [0, 60000]
|
||||
},
|
||||
mainLoading: false, // 画布loading
|
||||
nodeData: {}, // 当前节点的数据
|
||||
edgeData: {}, // 当前分支线的数据
|
||||
@@ -70,6 +104,7 @@
|
||||
taskMakeKey: 0, // 是否刷新任务编排
|
||||
nodeSliderKey: 0, // 节点信息抽屉组件key
|
||||
edgeSliderKey: 0, // 分支线抽屉信息组件key
|
||||
flowModeDialogKey: 0, // 前置作业流连线弹窗组件key
|
||||
nodeDrawer: { // 节点信息抽屉
|
||||
show: false,
|
||||
width: 536,
|
||||
@@ -95,7 +130,18 @@
|
||||
}
|
||||
],
|
||||
edges: [],
|
||||
graph: null
|
||||
graph: null,
|
||||
flowModeDialog: { // 前置作业流连线模式选择弹窗
|
||||
show: false,
|
||||
curObj: {}, // 当前前置作业流的信息
|
||||
preEdges: [], // 当前前置作业流节点的出线集
|
||||
childDialog: { // 当前前置作业流节点的详情弹框
|
||||
footerShow: false,
|
||||
show: false,
|
||||
width: 960,
|
||||
title: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -177,6 +223,63 @@
|
||||
this.mainLoading = false
|
||||
}, 1000)
|
||||
},
|
||||
// 处理前置作业流节点连线模式确认
|
||||
handleFlowAddEdgeConfirm() {
|
||||
if (this.$refs.addModeDialog.modeValue === 'flow') {
|
||||
setTimeout(() => {
|
||||
this.graph.addItem('edge', {
|
||||
id: getUUID(32, 16),
|
||||
source: this.flowModeDialog.curObj.sourceNode.get('id'),
|
||||
target: this.flowModeDialog.curObj.targetNode.get('id'),
|
||||
gateWay: {
|
||||
name: '', // 分支名
|
||||
expression: '' // 条件表达式
|
||||
}
|
||||
})
|
||||
}, 100)
|
||||
this.flowModeDialog.show = false
|
||||
} else {
|
||||
const edges = this.flowModeDialog.curObj.sourceNode.getEdges()
|
||||
// 表明已有其他前置连线,收集前置节点连线
|
||||
if (edges.length) {
|
||||
this.flowModeDialog.preEdges = edges.filter(item => {
|
||||
return item.getModel().hasOwnProperty('label')
|
||||
})
|
||||
}
|
||||
this.flowModeDialog.childDialog.title = this.flowModeDialog.curObj.sourceNode.getModel().name
|
||||
this.flowModeDialog.childDialog.footerShow = true
|
||||
this.flowModeDialog.childDialog.show = true
|
||||
}
|
||||
},
|
||||
// 处理选择前置作业流中的某个作业节点确认
|
||||
handlePreFlowNOdeAddConfirm() {
|
||||
if (!this.$refs.preFlowCanvas.currentChooseNode) {
|
||||
this.$cwMessage('当前作业节点未选择,至少选择一个作业节点!', 'warning')
|
||||
} else {
|
||||
const _this = this
|
||||
setTimeout(() => {
|
||||
const label = `${_this.$refs.preFlowCanvas.currentChooseNode.name}→${_this.flowModeDialog.curObj.targetNode.getModel().name}`
|
||||
this.graph.addItem('edge', {
|
||||
id: getUUID(32, 16),
|
||||
source: _this.flowModeDialog.curObj.sourceNode.get('id'),
|
||||
target: _this.flowModeDialog.curObj.targetNode.get('id'),
|
||||
label: label.length > 10 ? `${label.substr(0, 10)}...` : label,
|
||||
rely_node: {
|
||||
name: label,
|
||||
label: label.length > 10 ? `${label.substr(0, 10)}...` : label,
|
||||
content: _this.$refs.preFlowCanvas.currentChooseNode.content,
|
||||
id: _this.$refs.preFlowCanvas.currentChooseNode.id
|
||||
},
|
||||
gateWay: {
|
||||
name: '', // 分支名
|
||||
expression: '' // 条件表达式
|
||||
}
|
||||
})
|
||||
_this.flowModeDialog.childDialog.show = false
|
||||
_this.flowModeDialog.show = false
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
// 处理获取作业流数据
|
||||
getSingleJobFlow() {
|
||||
this.$api.process.retrieve(parseInt(this.$route.query.job_flow_data)).then(res => {
|
||||
@@ -355,7 +458,11 @@
|
||||
initGraphEvent() {
|
||||
// 监听节点选中
|
||||
this.graph.on('after-node-selected', e => {
|
||||
return this.handleOpenNodeDrawer(e)
|
||||
if (e.item.getModel().nodeType !== 3) {
|
||||
this.handleOpenNodeDrawer(e)
|
||||
} else {
|
||||
this.handleOpenFlowDrawer(e)
|
||||
}
|
||||
})
|
||||
// 监听节点连线
|
||||
this.graph.on('before-edge-add', (flag, obj) => {
|
||||
@@ -378,6 +485,21 @@
|
||||
this.handleDeleteNode(e.item)
|
||||
})
|
||||
},
|
||||
handleOpenFlowDrawer(e) {
|
||||
this.flowModeDialog.preEdges = []
|
||||
const edges = e.item.getEdges()
|
||||
console.log(123, e.item.getModel())
|
||||
// 表明已有其他前置连线,收集前置节点连线
|
||||
if (edges.length) {
|
||||
this.flowModeDialog.preEdges = edges.filter(item => {
|
||||
return item.getModel().hasOwnProperty('label')
|
||||
})
|
||||
}
|
||||
this.flowModeDialog.curObj = { sourceNode: e.item }
|
||||
this.flowModeDialog.childDialog.title = e.item.getModel().name
|
||||
this.flowModeDialog.childDialog.footerShow = false
|
||||
this.flowModeDialog.childDialog.show = true
|
||||
},
|
||||
// 打开分支连线抽屉
|
||||
handleOpenEdgeInfo(e) {
|
||||
const model = e.item.get('model')
|
||||
@@ -663,8 +785,7 @@
|
||||
x,
|
||||
y
|
||||
}
|
||||
console.log('sad', model)
|
||||
|
||||
console.log('model', model)
|
||||
if (model.endUuid !== '' && this.graph.findById(model.endUuid)) {
|
||||
return this.$cwMessage('相同作业流已存在,不可重复添加', 'warning')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div id="addModeDialog">
|
||||
<bk-radio-group v-model="modeValue">
|
||||
<bk-radio :value="'node'" style="margin-right: 24px;">前置节点</bk-radio>
|
||||
<bk-radio :value="'flow'">前置作业流</bk-radio>
|
||||
</bk-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
modeValue: 'flow'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -5,7 +5,7 @@
|
||||
<i class="iconfont icon-mianxingtubiao-jibenxinxi" :style="{ color: isActive === 1 ? '#3A84FF' : '#979BA5' }"></i>
|
||||
<p :style="{ color: isActive === 1 ? '#3A84FF' : '#333333' }">基本信息</p>
|
||||
</div>
|
||||
<div class="box" style="margin-left: 36px;" @click="handleOpenTaskMake">
|
||||
<div class="box" style="margin-left: 36px;" @click="handleOpenTaskMake" v-if="!disabled">
|
||||
<i class="iconfont icon-mianxingtubiao-renwubianpai" :style="{ color: isActive === 2 ? '#3A84FF' : '#979BA5' }"></i>
|
||||
<p :style="{ color: isActive === 2 ? '#3A84FF' : '#333333' }">任务编排</p>
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="right">
|
||||
<i class="iconfont icon-xianxingtubiao-fuwei" title="复位" @click="handleReset"></i>
|
||||
<i class="iconfont icon-xianxingtubiao-yijianbianpai" title="一键排版" @click="handleLayoutSetting"></i>
|
||||
<i class="iconfont icon-xianxingtubiao-baocun" title="保存" @click="handleSave"></i>
|
||||
<i class="iconfont icon-xianxingtubiao-baocun" title="保存" @click="handleSave" v-if="!disabled"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -48,7 +48,8 @@
|
||||
validatorFlag: true, // 上传前校验位
|
||||
midNodes: [], // 保存前节点数据处理
|
||||
midLines: [],
|
||||
isActive: 0
|
||||
isActive: 0,
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -366,11 +367,11 @@
|
||||
this.checkClose()
|
||||
// 表明已形成闭环,开始表单校验
|
||||
if (this.validatorFlag) {
|
||||
this.checnkFrom()
|
||||
this.checkFrom()
|
||||
}
|
||||
}
|
||||
},
|
||||
checnkFrom() {
|
||||
checkFrom() {
|
||||
this.father_this.$refs.baseInfo.$refs.form.validate().then(validator => {
|
||||
this.validatorFlag = true
|
||||
// let flag = false
|
||||
@@ -420,19 +421,6 @@
|
||||
params.description = this.father_this.$refs.baseInfo.form.jobFlowDescribe // 作业流描述
|
||||
params.var_table = this.father_this.$refs.baseInfo.form.var_table // 变量表值
|
||||
params.category = this.father_this.$refs.baseInfo.form.category // 跑批系统id
|
||||
// 有前置依赖
|
||||
if (this.father_this.$refs.baseInfo.form.pre_commands[0].key !== '') {
|
||||
if (!this.father_this.$refs.baseInfo.form.pre_category) {
|
||||
return this.$cwMessage('有前置依赖,前置跑批系统不能为空,请选择!', 'warning')
|
||||
}
|
||||
if (!this.father_this.$refs.baseInfo.form.pre_agent) {
|
||||
return this.$cwMessage('有前置依赖,前置Agent不能为空,请选择!', 'warning')
|
||||
}
|
||||
// 到了这里说明此时有前置依赖,且前置跑批系统和前置Agent都不为空
|
||||
params.pre_category = this.father_this.$refs.baseInfo.form.pre_category // 作业流前置跑批id
|
||||
params.pre_agent = this.father_this.$refs.baseInfo.form.pre_agent // 作业流前置agent
|
||||
params.pre_commands = this.father_this.$refs.baseInfo.form.pre_commands // 作业流前置依赖
|
||||
}
|
||||
// 有前置文件路径
|
||||
if (this.father_this.$refs.baseInfo.form.file_dependence.file_path !== '') {
|
||||
if (!this.father_this.$refs.baseInfo.form.pre_category) {
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
</div>
|
||||
<div class="footer" v-if="!disabled">
|
||||
<bk-button theme="primary" @click="handleConfim" style="margin-right: 8px;" :loading="isChecking">确定</bk-button>
|
||||
<bk-button @click="handleCancel">取消</bk-button>
|
||||
<bk-button @click="handleCancel">保存为模板</bk-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -270,7 +270,24 @@
|
||||
},
|
||||
// 处理取消
|
||||
handleCancel() {
|
||||
this.$emit('node-drawer-close', true)
|
||||
this.isChecking = true
|
||||
this.$refs.form.validate().then(validator => {
|
||||
this.isChecking = false
|
||||
this.$emit('update-node-data', this.form, this.nodeData.id)
|
||||
this.form['name'] = this.form['node_name']
|
||||
this.form['component_code'] = 'http_request'
|
||||
this.$api.content.create(this.form).then(res => {
|
||||
if (res.result) {
|
||||
this.$cwMessage('保存成功!', 'success')
|
||||
} else {
|
||||
this.$cwMessage(res.message, 'error')
|
||||
}
|
||||
})
|
||||
this.$emit('node-drawer-close', true)
|
||||
}, validator => {
|
||||
this.isChecking = false
|
||||
// alert(`${validator.field}:${validator.content}`)
|
||||
})
|
||||
},
|
||||
// 处理删除前置条件检测命令
|
||||
handleDeleteCommand(index) {
|
||||
|
||||
338
web/src/views/job_flow_mgmt/single_job_flow/preFlowCanvas.vue
Normal file
338
web/src/views/job_flow_mgmt/single_job_flow/preFlowCanvas.vue
Normal file
@@ -0,0 +1,338 @@
|
||||
<template>
|
||||
<div id="preFlowCanvas" v-bkloading="{ isLoading: mainLoading, zIndex: 999999 }">
|
||||
<div class="header">
|
||||
<div class="select-node">
|
||||
<span>已使用依赖的节点:</span>
|
||||
<span class="text" v-if="allChooseNode.length"
|
||||
v-bk-tooltips="{ placement: 'bottom', width: 300, content: `${allChooseNode.join(', ')}` }">{{allChooseNode.join(', ')}}</span>
|
||||
<span v-else>- -</span>
|
||||
</div>
|
||||
<div class="current-select">
|
||||
<span>当前选择的节点:</span>
|
||||
<span class="text" v-if="currentChooseNode" :title="`${currentChooseNode.name}`">{{currentChooseNode.name}}</span>
|
||||
<span v-else>- -</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="mainFlow" class="mainFlow" id="mainFlow"></div>
|
||||
<div style="height: 150px;width: 150px;position: absolute;bottom: 0px;right: 0px;border: 1px solid #ccc;" ref="miniMap"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import baseNodes from './baseNode.js'
|
||||
import options from './options.js'
|
||||
import registerFactory from '@/components/graph/graph.js'
|
||||
import G6 from '@antv/g6'
|
||||
import {
|
||||
getUUID
|
||||
} from '../../../common/util.js'
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
preEdges: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
allChooseNode: [],
|
||||
currentChooseNode: null,
|
||||
jobFlowFrom: null,
|
||||
graph: null,
|
||||
mainLoading: false,
|
||||
basicNodes: [{
|
||||
...baseNodes[0],
|
||||
id: getUUID(32, 16)
|
||||
},
|
||||
{
|
||||
...baseNodes[1],
|
||||
id: getUUID(32, 16)
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getSingleJobFlow()
|
||||
this.allChooseNode = this.preEdges.map(item => {
|
||||
const model = item.getModel()
|
||||
return `${model.rely_node.name}`.split('→')[0]
|
||||
})
|
||||
this.allChooseNode = Array.from(new Set(this.allChooseNode))
|
||||
},
|
||||
mounted() {
|
||||
// 创建画布并绑定相关事件
|
||||
this.$nextTick(() => {
|
||||
this.createGraphic()
|
||||
this.initGraphEvent()
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.graph.destroy()
|
||||
},
|
||||
methods: {
|
||||
// 初始化graph监听函数
|
||||
initGraphEvent() {
|
||||
// 监听节点选中
|
||||
this.graph.on('after-node-selected', e => {
|
||||
const model = e.item.getModel()
|
||||
if (model.nodeType !== 3) {
|
||||
this.currentChooseNode = model
|
||||
}
|
||||
})
|
||||
},
|
||||
getSingleJobFlow() {
|
||||
this.mainLoading = true
|
||||
const model = this.options.sourceNode.getModel()
|
||||
console.log(11, model)
|
||||
this.$api.process.retrieve(model.content).then(res => {
|
||||
if (res.result) {
|
||||
this.jobFlowFrom = res.data
|
||||
this.handleRender(true)
|
||||
} else {
|
||||
this.$cwMessage(res.message, 'error')
|
||||
this.mainLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
handleRender(detail) {
|
||||
this.mainLoading = true
|
||||
const _this = this
|
||||
setTimeout(() => {
|
||||
const data = {
|
||||
edges: _this.jobFlowFrom.pipeline_tree.lines.map(line => {
|
||||
const item = {
|
||||
detail: detail,
|
||||
id: getUUID(32, 16),
|
||||
source: line.from,
|
||||
target: line.to,
|
||||
gateWay: {
|
||||
name: line.hasOwnProperty('gateWay') ? line.gateWay.name : '',
|
||||
expression: line.hasOwnProperty('gateWay') ? line.gateWay
|
||||
.expression : ''
|
||||
}
|
||||
}
|
||||
if (item.gateWay.name !== '') {
|
||||
item.label = line.gateWay.name.length > 7
|
||||
? `${item.gateWay.name.substr(0, 7)}...` : line.gateWay.name
|
||||
}
|
||||
if (line.hasOwnProperty('rely_node')) {
|
||||
item.rely_node = line.rely_node
|
||||
item.label = line.rely_node.label
|
||||
}
|
||||
return item
|
||||
}),
|
||||
nodes: _this.jobFlowFrom.pipeline_tree.nodes.map((node, index) => {
|
||||
let style = {}
|
||||
if (node.type === 0 || node.type === 1) {
|
||||
style = {
|
||||
fill: '#fff',
|
||||
stroke: '#DCDEE5',
|
||||
lineWidth: 1,
|
||||
r: 24
|
||||
}
|
||||
} else {
|
||||
style = {
|
||||
width: 154,
|
||||
height: 40,
|
||||
radius: 20,
|
||||
stroke: '#DCDEE5',
|
||||
lineWidth: 1,
|
||||
iconCfg: {
|
||||
fill: '#3a84ff'
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
detail: detail,
|
||||
label: node.name.length > 8 ? `${node.name.substr(0, 8)}...` : node
|
||||
.name,
|
||||
name: node.name,
|
||||
icon: node.ico,
|
||||
id: node.hasOwnProperty(node.end_uuid) ? node.end_uuid : node.uuid,
|
||||
endUuid: node.hasOwnProperty(node.end_uuid) ? node.end_uuid
|
||||
: '', // 有enduuid表明为作业流,加上enduuid,没有为空
|
||||
x: Number(node.left),
|
||||
y: Number(node.top),
|
||||
nodeType: node.type,
|
||||
type: (node.type === 0 || node.type === 1) ? 'circle-node'
|
||||
: 'rect-node',
|
||||
labelCfg: {
|
||||
style: {
|
||||
textAlign: (node.type === 0 || node.type === 1) ? 'center'
|
||||
: 'left'
|
||||
}
|
||||
},
|
||||
style: {
|
||||
...style
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
_this.graph.read(data)
|
||||
// 如果有前置已选节点,需要给它加上已选的样式
|
||||
if (this.preEdges.length) {
|
||||
const nodes = this.graph.getNodes()
|
||||
this.preEdges.forEach(edge => {
|
||||
nodes.forEach(node => {
|
||||
if (edge.getModel().rely_node.id === node.getModel().id) {
|
||||
const model = node.getModel()
|
||||
model.choose = true
|
||||
this.graph.updateItem(model.id, model)
|
||||
node.setState('nodeState:preselected')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
_this.mainLoading = false
|
||||
}, 300)
|
||||
},
|
||||
// 创建画布
|
||||
createGraphic() {
|
||||
this.mainLoading = true
|
||||
const _this = this
|
||||
// 创建内容超出提示
|
||||
const tooltip = new G6.Tooltip({
|
||||
offsetX: -10,
|
||||
offsetY: -10,
|
||||
itemTypes: ['node', 'edge'],
|
||||
// 自定义 tooltip 内容
|
||||
getContent: (e) => {
|
||||
let content = ''
|
||||
if (e.item._cfg.type === 'edge' && e.target.cfg.type !== 'path') {
|
||||
content = e.item.getModel().gateWay.name
|
||||
} else {
|
||||
content = e.item.getModel().name
|
||||
}
|
||||
const outDiv = document.createElement('div')
|
||||
outDiv.innerHTML = `<span>${content}</span>`
|
||||
return outDiv
|
||||
},
|
||||
shouldBegin(e) {
|
||||
const model = e.item.get('model')
|
||||
if (e.item._cfg.type === 'edge') {
|
||||
if (e.target.cfg.type !== 'path' && !e.target.cfg.attrs.hasOwnProperty(
|
||||
'fontFamily')) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
// 触发方式,只有在内容超出8个字符的情况下才触发
|
||||
if (model.nodeType === 0 || model.nodeType === 1 || model.name.length <= 8) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
const minimap = new G6.Minimap({
|
||||
container: _this.$refs.miniMap,
|
||||
size: [150, 150]
|
||||
})
|
||||
// 工厂函数注册自定义节点
|
||||
const cfg = registerFactory(G6, {
|
||||
container: 'mainFlow',
|
||||
width: 880,
|
||||
height: 500,
|
||||
fitView: true,
|
||||
maxZoom: 1, // 最大缩放比例
|
||||
animate: true, // Boolean,可选,切换布局时是否使用动画过度
|
||||
defaultNode: {
|
||||
...options.defaultNode
|
||||
},
|
||||
modes: {
|
||||
default: [
|
||||
...options.modes,
|
||||
{
|
||||
type: 'drag-node',
|
||||
shouldBegin: e => {
|
||||
if (e.target.cfg.isAnchor) return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
defaultEdge: {
|
||||
...options.defaultEdge
|
||||
},
|
||||
// 覆盖全局样式
|
||||
nodeStateStyles: {
|
||||
...options.nodeStateStyles
|
||||
},
|
||||
// 默认边不同状态下的样式集合
|
||||
edgeStateStyles: {
|
||||
...options.edgeStateStyles
|
||||
},
|
||||
// linkCenter: true,
|
||||
// plugins: this.$route.query.type === 'detail' ? [tooltip] : [menu, tooltip],
|
||||
plugins: [tooltip, minimap]
|
||||
})
|
||||
// 创建graph实例
|
||||
this.graph = new G6.Graph(cfg)
|
||||
// const data = {
|
||||
// nodes: this.basicNodes
|
||||
// }
|
||||
// this.graph.read(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
#preFlowCanvas {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
.header {
|
||||
display: flex;
|
||||
margin-bottom: 15px;
|
||||
font-size: 14px;
|
||||
color: #313237;
|
||||
|
||||
.select-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.text {
|
||||
max-width: 350px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.current-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 55px;
|
||||
|
||||
.text {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
// width: 250px;
|
||||
// white-space:nowrap;
|
||||
// overflow:hidden;
|
||||
// text-overflow:ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
#mainFlow {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
position: relative;
|
||||
background-image: linear-gradient(90deg, rgba(180, 180, 180, 0.15) 10%, rgba(0, 0, 0, 0) 10%), linear-gradient(rgba(180, 180, 180, 0.15) 10%, rgba(0, 0, 0, 0) 10%);
|
||||
background-size: 10px 10px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid rgba(180, 180, 180, 0.15);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -9,12 +9,12 @@
|
||||
</div>
|
||||
<div class="box">
|
||||
<bk-compose-form-item head-background-color="#fff">
|
||||
<bk-select :clearable="false" style="width: 94px;" v-model="form.makeType" placeholder="请选择" @change="handleMakeTypeChange"
|
||||
:disabled="disabled ? true : controlType === 'calendar' ? false : true">
|
||||
<bk-select :clearable="false" style="width: 111px;" v-model="form.makeType" placeholder="请选择" @change="handleMakeTypeChange"
|
||||
:disabled="false">
|
||||
<bk-option v-for="(item, index) in makeList" :key="index" :id="item.value" :name="item.label">
|
||||
</bk-option>
|
||||
</bk-select>
|
||||
<bk-input clearable style="width: 380px;" :placeholder="'请输入'" :right-icon="'bk-icon icon-search'"
|
||||
<bk-input clearable style="width: 356px;margin-left: 8px" :placeholder="'请输入'" :right-icon="'bk-icon icon-search'"
|
||||
v-model="form.name" @right-icon-click="handleSearch" @enter="handleSearch" :disabled="disabled">
|
||||
</bk-input>
|
||||
</bk-compose-form-item>
|
||||
@@ -52,63 +52,55 @@
|
||||
form: {
|
||||
system_id: '', // 跑批系统id
|
||||
agent_id: '', // agent
|
||||
makeType: 0, // 是否编排
|
||||
makeType: 3, // 是否编排
|
||||
name: '' // 作业名
|
||||
},
|
||||
makeList: [{
|
||||
label: '已编排',
|
||||
value: 1
|
||||
}, {
|
||||
label: '未编排',
|
||||
value: 0
|
||||
}],
|
||||
makeList: [
|
||||
{
|
||||
label: '逻辑节点',
|
||||
value: 3
|
||||
}, {
|
||||
label: '空节点模板',
|
||||
value: 0
|
||||
}, {
|
||||
label: '节点模板',
|
||||
value: 2
|
||||
}, {
|
||||
label: '子流程',
|
||||
value: 1
|
||||
}],
|
||||
jobList: [
|
||||
{
|
||||
'id': 45,
|
||||
'creator': 'product',
|
||||
'name': 'HTTP请求',
|
||||
'type': 2,
|
||||
'nodeType': 2,
|
||||
'create_time': '2021-08-10 17:34:57',
|
||||
'description': 'xx',
|
||||
'editor': 'product',
|
||||
'edit_time': '2021-11-15 11:55:06',
|
||||
'total_run_count': 145,
|
||||
'last_run_at': '2021-11-15 11:55:06',
|
||||
'exit_code': '',
|
||||
'station': 'agent11',
|
||||
'ip': '192.168.163.185',
|
||||
'os': 'linux centos',
|
||||
'category': 'v17',
|
||||
'process': '参数传递_test2_20210818191900,stop_test,重新执行测试,参数传递_test2,外部作业流_test1',
|
||||
'account': 'root',
|
||||
'script_type': 4,
|
||||
'script_content': '1',
|
||||
'script_timeout': 8600,
|
||||
'name': '条件网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'icon': 'e6d9'
|
||||
},
|
||||
{
|
||||
'id': 45,
|
||||
'id': 46,
|
||||
'creator': 'product',
|
||||
'name': '條件分支',
|
||||
'name': '并行网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'create_time': '2021-08-10 17:34:57',
|
||||
'description': 'xx',
|
||||
'editor': 'product',
|
||||
'edit_time': '2021-11-15 11:55:06',
|
||||
'total_run_count': 145,
|
||||
'last_run_at': '2021-11-15 11:55:06',
|
||||
'exit_code': '',
|
||||
'station': 'agent11',
|
||||
'ip': '192.168.163.185',
|
||||
'os': 'linux centos',
|
||||
'category': 'v17',
|
||||
'process': '参数传递_test2_20210818191900,stop_test,重新执行测试,参数传递_test2,外部作业流_test1',
|
||||
'account': 'root',
|
||||
'script_type': 4,
|
||||
'script_content': '1',
|
||||
'script_timeout': 8600
|
||||
'icon': 'e6d9'
|
||||
},
|
||||
{
|
||||
'id': 47,
|
||||
'creator': 'product',
|
||||
'name': '汇聚网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'icon': 'e6d9'
|
||||
},
|
||||
{
|
||||
'id': 48,
|
||||
'creator': 'product',
|
||||
'name': '条件并行网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'icon': 'e6d9'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -160,10 +152,34 @@
|
||||
this.jobListLoading = false
|
||||
})
|
||||
},
|
||||
// 获取节点模板
|
||||
getNodeTemplateList(str) {
|
||||
this.jobListLoading = true
|
||||
const params = {
|
||||
category: this.form.system_id
|
||||
}
|
||||
if (str === 'search') {
|
||||
params.name = this.form.name
|
||||
}
|
||||
this.$api.content.list(params).then(res => {
|
||||
if (res.result) {
|
||||
this.jobList = res.data.items.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
nodeType: 2,
|
||||
endUuid: item.end_uuid,
|
||||
icon: 'e6d9'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$cwMessage(res.message, 'error')
|
||||
}
|
||||
this.jobListLoading = false
|
||||
})
|
||||
},
|
||||
// 获取作业
|
||||
getJobList(str) {
|
||||
if (this.form.agent_id === '') return
|
||||
this.jobListLoading = true
|
||||
// this.jobListLoading = true
|
||||
const params = {
|
||||
station: this.form.agent_id
|
||||
}
|
||||
@@ -209,19 +225,51 @@
|
||||
this.jobList = []
|
||||
this.form.name = ''
|
||||
this.form.agent_id = ''
|
||||
if (this.form.system_id !== '') {
|
||||
// 编排类型切换为未编排时,当前跑批系统id不为空,默认获取agent列表
|
||||
if (!this.form.makeType) {
|
||||
this.form.system_id = this.midRunId
|
||||
if (this.form.system_id !== '') {
|
||||
this.getAgentList()
|
||||
// 编排类型切换为未编排时,当前跑批系统id不为空,默认获取agent列表
|
||||
if (this.form.makeType === 0) {
|
||||
this.getNodeTemplateList()
|
||||
} else if (this.form.makeType === 1) {
|
||||
// 编排类型切换成已编排时,记录此时的跑批id
|
||||
this.midRunId = this.form.system_id
|
||||
// 编排类型切换为已编排时,当前跑批系统id不为空,默认获取作业流列表
|
||||
this.getJobFlowList()
|
||||
} else if (this.form.makeType === 2) {
|
||||
this.getNodeTemplateList()
|
||||
} else if (this.form.makeType === 3) {
|
||||
this.jobList = [
|
||||
{
|
||||
'id': 45,
|
||||
'creator': 'product',
|
||||
'name': '条件网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'icon': 'e6d9'
|
||||
},
|
||||
{
|
||||
'id': 46,
|
||||
'creator': 'product',
|
||||
'name': '并行网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'icon': 'e6d9'
|
||||
},
|
||||
{
|
||||
'id': 47,
|
||||
'creator': 'product',
|
||||
'name': '汇聚网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'icon': 'e6d9'
|
||||
},
|
||||
{
|
||||
'id': 48,
|
||||
'creator': 'product',
|
||||
'name': '条件并行网关',
|
||||
'type': 4,
|
||||
'nodeType': 4,
|
||||
'icon': 'e6d9'
|
||||
}
|
||||
} else {
|
||||
// 编排类型切换成已编排时,记录此时的跑批id
|
||||
this.midRunId = this.form.system_id
|
||||
// 编排类型切换为已编排时,当前跑批系统id不为空,默认获取作业流列表
|
||||
this.getJobFlowList()
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// 处理查询
|
||||
|
||||
@@ -84,20 +84,12 @@
|
||||
<bk-table-column label="操作" width="180">
|
||||
<template slot-scope="props">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<bk-button class="mr10" theme="primary" text @click="handleImplement(props.row)"
|
||||
v-if="auth.operate">执行</bk-button>
|
||||
<bk-button class="mr10" theme="primary" text @click="handleOpenUpdate(props.row)"
|
||||
v-if="auth.modify">修改</bk-button>
|
||||
<bk-button class="mr10" theme="primary" text @click="handleClone(props.row)" v-if="auth.modify">克隆
|
||||
</bk-button>
|
||||
<bk-button class="mr10" theme="primary" text @click="handleDelete(props.row)" v-if="auth.del">删除
|
||||
</bk-button>
|
||||
<bk-popover ext-cls="dot-menu" placement="bottom-start" theme="dot-menu light" trigger="click"
|
||||
:arrow="false" :distance="0" offset="15">
|
||||
<span class="dot-menu-trigger"></span>
|
||||
<ul class="dot-menu-list" slot="content">
|
||||
<li class="dot-menu-item" v-if="auth.modify" @click="handleClone(props.row)">克隆</li>
|
||||
<li class="dot-menu-item" @click="handleJumpHistory(props.row)">执行历史</li>
|
||||
</ul>
|
||||
</bk-popover>
|
||||
</div>
|
||||
</template>
|
||||
</bk-table-column>
|
||||
|
||||
@@ -107,12 +107,9 @@
|
||||
</bk-col>
|
||||
</bk-row>
|
||||
</template>
|
||||
<bk-form-item label="脚本内容:" :error-display-type="'normal'" :required="true"
|
||||
:property="'data.script_content'"
|
||||
v-show="!(form.data.script_type === 6) && !(form.data.script_type === 7)">
|
||||
<!-- <bk-input :type="'textarea'" style="width: 720px;" :rows="10" ext-cls="custom-textarea" v-model="form.data.script_content"></bk-input> -->
|
||||
<editor :width="'720px'" :height="'300px'" ref="editor" :codes="form.data.script_content">
|
||||
</editor>
|
||||
<bk-form-item label="脚本内容:" :error-display-type="'normal'" :required="true" :property="'data.script_content'" v-show="!(form.data.script_type === 6) && !(form.data.script_type === 7)">
|
||||
<bk-input :type="'textarea'" style="width: 720px;" :rows="10" ext-cls="custom-textarea" v-model="form.data.script_content">
|
||||
</bk-input>
|
||||
</bk-form-item>
|
||||
<bk-form-item label="作业退出码:">
|
||||
<bk-input placeholder="作业退出码" v-model="form.exit_code"></bk-input>
|
||||
@@ -139,14 +136,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import editor from '@/components/monacoEditor'
|
||||
import {
|
||||
deepClone, isJson
|
||||
} from '../../common/util.js'
|
||||
import { validateURL } from '../../common/validate.js'
|
||||
export default {
|
||||
components: {
|
||||
editor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -585,7 +580,7 @@
|
||||
},
|
||||
// 获取跑批系统
|
||||
getRunSysList() {
|
||||
this.formLoading = true
|
||||
// this.formLoading = true
|
||||
this.runSysList = []
|
||||
},
|
||||
// 设置默认编辑器
|
||||
|
||||
@@ -234,7 +234,7 @@
|
||||
this.graph.on('node:click', e => {
|
||||
const model = e.item.get('model')
|
||||
// 开始节点,结束节点,作业流节点不做处理
|
||||
if (model.nodeType === 0 || model.nodeType === 1 || model.nodeType === 3) {
|
||||
if (model.nodeType === 0 || model.nodeType === 1) {
|
||||
return false
|
||||
}
|
||||
this.nodeData = {
|
||||
|
||||
Reference in New Issue
Block a user