feature:a

This commit is contained in:
charlesxie
2022-02-10 18:46:26 +08:00
parent 366c0d6b53
commit c2fe6a5537
29 changed files with 1831 additions and 899 deletions

File diff suppressed because it is too large Load Diff

View 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,
},
),
]

View 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'),
),
]

View File

@@ -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")

View File

@@ -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",)

View File

@@ -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")

View File

@@ -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 构造出流程描述结构

View File

@@ -0,0 +1,5 @@
import uuid
def get_uuid():
return str(uuid.uuid4()).replace("-", "")

View File

@@ -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}}]}}

View File

@@ -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)),
]

View File

@@ -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)

View File

@@ -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': '作业流管理',

View File

@@ -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 状态

View File

@@ -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')
}

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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) {

View 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>

View File

@@ -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()
}
]
}
},
// 处理查询

View File

@@ -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>

View File

@@ -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 = []
},
// 设置默认编辑器

View File

@@ -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 = {