简易流水线表单设计

django+workflow

需求

希望把常见的定时任务可视化,或者做一个支持自定义表单的工单系统。

设计

前端支持自定义表单,表单的提交对应向rabbitmq的同名group里面发消息,

处理函数消费对应的group,并把结果返回至pipeline_ret group,我们的

程序负责处理返回结果,并且更新。期间穿插一些评论等。

代码部分

数据模型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from django.db import models

def local_timestamp(timestamp):
    """Convert datetime field to local timestamp."""
    return timestamp.astimezone(
        timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")


class Pipeline(models.Model):
    """Pipeline task template."""

    # 用于channel队列名称,结果需要放到rabbit对应的{name}_result channel中
    name = models.CharField(max_length=100, verbose_name='工作流标识符', unique=True)
    nickname = models.CharField(max_length=100, verbose_name='工作流显示名称')
    p_tag = models.CharField(max_length=50,
                             verbose_name='标签',
                             default='default')

    p_creator = models.CharField(max_length=50, verbose_name='创建人')
    # json format string
    html_form_json = models.TextField(verbose_name='表单类型')
    # 0: 禁用 1: 启用
    status = models.IntegerField(verbose_name='工作流可用状态', default=1)
    description = models.CharField(max_length=100, verbose_name='工作流描述')
    create_timestamp = models.DateTimeField(auto_now_add=True,
                                            verbose_name="创建时间戳")
    update_timestamp = models.DateTimeField(auto_now=True,
                                            verbose_name="更新时间戳")

    def to_json(self):
        """Json format of pipeline."""
        return {
            "id": self.id,
            "name": self.name,
            "nickname": self.nickname,
            "p_tag": self.p_tag,
            "p_creator": self.p_creator,
            "html_form_json": self.html_form_json,
            "status": self.status,
            "description": self.description,
            "create_timestamp": str(self.create_timestamp),
            "update_timestamp": str(self.update_timestamp)
        }


class PipelineTask(models.Model):
    """Pipeline actual task."""

    p_id = models.IntegerField(verbose_name='工作流id')
    data_json = models.TextField(verbose_name='表单数据')
    trigger = models.CharField(verbose_name="触发人", max_length=50, default='')
    # json format string
    result = models.TextField(verbose_name='任务结果')
    # -1: 就绪状态,等待运行 0: 立即放到运行队列 1: 运行中 2: 运行完成 3: 程序异常终止 4: 用户终止 5: 运行失败
    status = models.IntegerField(verbose_name='工作流任务状态')
    create_timestamp = models.DateTimeField(auto_now_add=True,
                                            verbose_name="创建时间戳")
    update_timestamp = models.DateTimeField(auto_now=True,
                                            verbose_name="更新时间戳")

    def to_json(self):
        """Json format of pipeline task."""
        return {
            "id": self.id,
            "p_id": self.p_id,
            "trigger": self.trigger,
            "data_json": self.data_json,
            "result": self.result,
            "status": self.status,
            "create_timestamp": local_timestamp(self.create_timestamp),
            "update_timestamp": local_timestamp(self.update_timestamp)
        }


class PipelineTaskComment(models.Model):
    """Pipeline task comments."""

    pt_id = models.IntegerField(verbose_name='工作流task id')
    creator = models.CharField(verbose_name='评论人',
                               max_length=50,
                               default='robot')
    c_type = models.CharField(verbose_name='评论类型', max_length=30)
    c_message = models.TextField(verbose_name='评论内容')
    create_timestamp = models.DateTimeField(auto_now_add=True,
                                            verbose_name="创建时间戳")

    def to_json(self):
        """Json format of pipeline task comments."""
        return {
            "id": self.id,
            "creator": self.creator,
            "pt_id": self.pt_id,
            "c_type": self.c_type,
            "c_message": self.c_message,
            "create_timestamp": local_timestamp(self.create_timestamp)
        }

这里注意:

  • html_form_json存放表单结构 每个 pipeline 都是一个流水线结构,每个流水线点击运行,就会生成对应的流水线任务 对应的实际数据存放在 data_json
  • 流水线任务/工单的评论发生在 任务开始和任务结束以及用户评论 那里

每次任务新建对应向 rabbitmq 发送一个信息,如下代码仅供参考,这里有个问题就是

逻辑处理

是否希望消息永久保存,这里见仁见智。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def AddPipelineTask(params):
    """Add pipeline_task with needed param."""
    if 'p_id' not in params or 'status' not in params:
        return fast_return(10835, extra=params['p_id'])
    p_id = params["p_id"]
    status = params["status"]
    data_json = params.get('data_json', '{}')

    # only add ready and send to running
    if status not in [0, -1]:
        return fast_return(10942, extra=status)

    pipeline_obj = Pipeline.objects.filter(id=p_id).first()
    if not pipeline_obj:
        logger.info("pipeline不存在 ", p_id)
        return fast_return(10933, extra=p_id)
    else:
        try:
            pipeline_task_obj = PipelineTask.objects.create(**params)
            # send to running task queue
            if status == 0:
                # will send to rabbit mq queue with pipeline name group
                logger.info('add pipeline task ' + str(pipeline_obj.name) +
                            str(data_json))
                try:
                    # add a comment to task detail page
                    comment = {
                        "pt_id": pipeline_task_obj.id,
                        "c_type": "auto",
                        "creator": "robot",
                        "c_message": "任务已经触发,即将运行!"
                    }
                    AddPipelineTaskComment(comment)

                    # send task info to mq
                    rb = RabbitMQ(host=RabbitMQ_HOST)
                    rb.send(exchange='',
                            queue=pipeline_obj.name,
                            durable=True,
                            body=json.dumps({
                                'args': pipeline_task_obj.data_json,
                                'task_id': pipeline_task_obj.id,
                                'pipeline_id': pipeline_obj.id,
                                'pipeline_name': pipeline_obj.name
                            }))
                except Exception as e:
                    logger.error('pipeline task send to mq error', str(e))
                finally:
                    return fast_return(code=10945,
                                       extra=pipeline_obj.name,
                                       data=pipeline_task_obj.to_json())

        except Exception as e:
            return fast_return(10935, extra=str(e))
        finally:
            pass
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Date: Mon Sep  5 09:57:26 2022
# Author: liuliancao <liuliancao@gmail.com>
"""Description: Rabbit mq related."""
import pika


class RabbitMQ(object):
    """Rabbit MQ related."""

    connection = None

    def __init__(self, host="127.0.0.1"):
        """Rabbitmq init related."""
        self.connection = pika.BlockingConnection(
            pika.ConnectionParameters(host))

    def send(self, queue='', durable=False, exchange='', body='{}'):
        """Rabbitmq send message."""
        ret = {"code": 0, "data": None, "message": "init"}
        if queue:
            try:
                with self.connection.channel() as ch:

                    ch.queue_declare(queue=queue, durable=durable)

                    if exchange:
                        ch.exchange_declare(exchange=exchange, durable=durable)

                    if durable:
                        sr = ch.basic_publish(exchange=exchange,
                                              routing_key=queue,
                                              body=body,
                                              properties=pika.BasicProperties(
                                                  delivery_mode=2, ))
                    else:
                        sr = ch.basic_publish(exchange=exchange,
                                              routing_key=queue,
                                              body=body)
                ret['code'] = 200
                ret['message'] = 'add message successfully ' + queue
                ret['data'] = sr
            except Exception as e:
                ret['message'] = 'add message failed ' + str(e)
                ret['data'] = None
                ret['code'] = 500
            finally:
                return ret
        return None

    def receive(self,
                queue='',
                durable=False,
                callback=None,
                auto_ack=True,
                exchange=''):
        """Rabbitmq receive message."""
        if queue:
            with self.connection.channel() as ch:
                if exchange:
                    ch.exchange_declare(exchange=exchange)
                ch.queue_declare(queue=queue, durable=durable)
                ch.basic_consume(queue=queue,
                                 auto_ack=True,
                                 on_message_callback=callback)
                ch.start_consuming()

由于我们需要实时监听消息的返回,所以这里需要写个manage.py的命令,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Date: Mon Sep  5 17:42:12 2022
# Author: liuliancao <liuliancao@gmail.com>
"""Description: Rabbitmq related."""
from django.core.management.base import BaseCommand

class ResultCatcher(object):
    """Pipeline result catcher."""

    def listen(self):
        """Fetch the result from the rabbitmq and update."""
        rb = RabbitMQ(host=RabbitMQ_HOST)
        rb.receive(queue=RabbitMQ_PipelineResultQueue,
                   durable=True,
                   callback=callback)


class Command(BaseCommand):
    """Used for manage.py command rabbitmq."""

    help = 'Run rabbit mq consumer for result catch.'

    def handle(self, *args, **kwargs):
        """Run rabbitmq."""
        print("running events pipeline result catcher...")
        rt = ResultCatcher()
        rt.listen()

前端部分

核心是前端的部分,前端负责生成和渲染对应的json字符串。

生成自定义表单页面

需要生成自定义表单,思路设计一个按钮点击弹出modal,

按需增加自己的表单,点击+则弹出对应的新的modal用用户选择类型等参数,

最终把这些拼接成一个json内容传回后端。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { Component, OnInit, Input } from '@angular/core';
import { DialogService } from 'ng-devui/modal';
import { AddHtmlFormComponent } from '../add-html-form/add-html-form.component';
import { FormConfig } from 'src/app/@shared/components/admin-form/admin-form.type';


@Component({
    selector: 'app-pipeline-add',
    templateUrl: './pipeline-add.component.html',
    styleUrls: ['./pipeline-add.component.css']
})
export class PipelineAddComponent implements OnInit {

    @Input() data: any;
    constructor(
        private dialogService: DialogService,
    ) { }

    ngOnInit(): void {
    }

    addFormField: boolean = false;

    storedItems: any[] = [];

    formSelectOptions = ["input", "textarea", "select"]
    HTMLFormJSON: FormConfig = {
        labelSize: 'sm',
        items: this.storedItems,
        showSubmit: false,
    };


    formConfig: FormConfig = {
        labelSize: 'sm',
        showSubmit: true,
        items: [
            {
                label: "label",
                prop: "label",
                type: "input",
            },
            {
                label: "prop",
                prop: "prop",
                type: "input",
            },
            {
                label: "fieldtype",
                prop: "type",
                type: "select",
                options: this.formSelectOptions,
            },
            {
                label: "补充字段",
                prop: "others",
                type: "textarea",
            }
        ]
    }
    defaultRowData = {
        label: '',
        prop: '',
        type: '',
        extraInfo: '',
        options: [],
    };

    openAddHtmlFormDialog(dialogtype?: string) {
        const results = this.dialogService.open({
            id: 'addHtmlFormService',
            maxHeight: '800px',
            title: '新增字段',
            content: AddHtmlFormComponent,
            backdropCloseable: true,
            onClose: () => {
                console.log('closed');
            },
            buttons: [
                {
                    cssClass: 'stress',
                    text: '确认',
                    handler: ($event: Event) => {
                        const newData = results.modalContentInstance.defaultRowData;
                        if (newData.type == "select") {
                            newData.options = newData.options.split(",");
                        }


                        this.HTMLFormJSON.items.push(newData);
                        console.log(this.HTMLFormJSON);
                        results.modalInstance.hide();
                    },
                },
                {
                    id: 'btn-cancel',
                    cssClass: 'common',
                    text: '取消',
                    handler: ($event: Event) => {
                        results.modalInstance.hide();
                    },
                },
            ],
            data: {
            },
        });
    }

    quickRowAdded(e: any) {
        const newData = { ...e };
        this.HTMLFormJSON.items.push(newData);
        this.addFormField = false;
        console.log(this.HTMLFormJSON);
    }

    quickRowCancel() {
        this.addFormField = false;
    }
}

弹出来的流水线添加的modal页面

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<form
      dForm
      style="margin: 20px auto;width: 800px"
  >
    <d-form-item>
      <d-form-label [required]="true">流水线名称</d-form-label>
      <d-form-control>
	<input
	    dTextInput
	    autocomplete="off"
	    name="name"
	    placeholder="请输入流水线名称"
	    [(ngModel)]="data.name" />
      </d-form-control>
    </d-form-item>
    <d-form-item>
      <d-form-label [required]="true">流水线显示名称</d-form-label>
      <d-form-control>
	<input
	    dTextInput
	    autocomplete="off"
	    name="nickname"
	    placeholder="请输入流水线显示名称"
	    [(ngModel)]="data.nickname" />
      </d-form-control>
    </d-form-item>

    <d-form-item>
      <d-form-label [required]="true">流水线描述信息</d-form-label>
      <d-form-control>
	<input
	    dTextInput
	    name="description"
	    [(ngModel)]="data.description"
	    placeholder="流水线描述信息"
	/>
      </d-form-control>
    </d-form-item>
    <d-form-item>
      <d-form-label [required]="true">标签</d-form-label>
      <d-form-control>
	<input
	    dTextInput
	    name="p_tag"
	    [(ngModel)]="data.p_tag"
	    placeholder="流水线标签"
	/>
      </d-form-control>
    </d-form-item>
    <d-form-item>
      <d-form-label [required]="true">表单结构</d-form-label>
      <d-form-control>
	<da-admin-form
	    *ngIf="HTMLFormJSON.items"
	    [formConfig]="HTMLFormJSON"
	    class="editable-row"
	></da-admin-form>

	<div
	    *ngIf="!addFormField"
	    (click)="openAddHtmlFormDialog()"
	    class="cursor-pointer"
	>
	  <d-icon [icon]="'icon-add'"></d-icon>
	  <span style="margin-left: 10px">添加新字段</span>
	</div>
	<div  class="edit-padding-fix">
	  <da-admin-form
	      *ngIf="addFormField"
	      [formConfig]="formConfig"
	      [formData]="defaultRowData"
	      class="editable-row"
	      (submitted)="quickRowAdded($event)"
	      (canceled)="quickRowCancel()"></da-admin-form>
	</div>
      </d-form-control>
    </d-form-item>
</form>

自定义字段的弹出页面

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'app-add-html-form',
    templateUrl: './add-html-form.component.html',
    styleUrls: ['./add-html-form.component.scss']
})
export class AddHtmlFormComponent implements OnInit {


    formSelectOptions = ["input", "textarea", "select"]

    defaultRowData = {
        label: '',
        prop: '',
        type: '',
        extraInfo: '',
        required: true,
        options: [],
    };

    showSelectOptions = false;

    checkRowData(e: any) {

        if (this.defaultRowData.type == 'select') {
            this.showSelectOptions = true;
        } else {
            this.showSelectOptions = false;
        }
    }

    onRequiredChange(e: any) {
        this.defaultRowData.required = !this.defaultRowData.required;
    }

    constructor() { }
    ngOnInit(): void {
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<form
  dForm
  style="margin: 20px auto">
  <d-form-item>
    <d-form-label [required]="true">label</d-form-label>
    <d-form-control>
      <input
	dTextInput
	  autocomplete="off"
			name="label"
			placeholder="请输入表单显示名"
			[(ngModel)]="defaultRowData.label" />
    </d-form-control>
  </d-form-item>
  <d-form-item>
    <d-form-label [required]="true">type</d-form-label>
    <d-form-control>
      <d-select
	[options]="formSelectOptions"
	  [(ngModel)]="defaultRowData.type"
	  (ngModelChange)="checkRowData($event)"
	  name="type"
	  placeholder="请选择表单类型"
	  [allowClear]="true"
      ></d-select>
    </d-form-control>
  </d-form-item>

  <d-form-item *ngIf="showSelectOptions">
    <d-form-label [required]="true">options</d-form-label>
    <d-form-control>
      <input
	dTextInput
	  autocomplete="off"
			name="options"
			placeholder="请输入选择项,以空格或逗号分隔"
			[(ngModel)]="defaultRowData.options" />
    </d-form-control>
  </d-form-item>


  <d-form-item>
    <d-form-label [required]="true">prop</d-form-label>
    <d-form-control>
      <input
	dTextInput
	  autocomplete="off"
			name="prop"
			placeholder="请输入表单字段名"
			[(ngModel)]="defaultRowData.prop" />
    </d-form-control>
  </d-form-item>

  <d-form-item>
    <d-form-label [required]="true">是否必填</d-form-label>
    <d-form-control extraInfo="选择表示此参数是必填的,不选表示参数可选">
      <d-checkbox [label]="''" [isShowTitle]="false" (change)="onRequiredChange($event)" [ngModel]="defaultRowData.required"></d-checkbox>
    </d-form-control>
  </d-form-item>

  <d-form-item>
    <d-form-label [required]="true">extraInfo</d-form-label>
    <d-form-control>
      <input
	dTextInput
	  autocomplete="off"
			name="tips"
			placeholder="请输入额外帮助信息"
			[(ngModel)]="defaultRowData.extraInfo" />
    </d-form-control>
  </d-form-item>
</form>
显示我们的自定义表单

对应流水线的显示,后端返回对应的html_form_json,前端只需要遍历渲染即可

对应的页面html部分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<h2>流水线: &nbsp; {{pipeline.nickname}} ({{pipeline.name}}) &nbsp;&nbsp;
  <d-icon
      [icon]="'icon-star'"
  ></d-icon>
  <a href="/pipeline/tasks?p_id={{pipeline.id}}">任务记录</a>
</h2>
<hr>
<h3>在线提交</h3>
<form
    dForm
    ngForm
    (dSubmit)="submitForm($event)"
    [labelAlign]="'end'"
    style="margin: 20px auto">
  <d-form-item *ngFor="let item of formConfig.items">
    <d-form-label [required]="item.required">{{ item.label }}: </d-form-label>
    <d-form-control [extraInfo]="item.extraInfo">
      <input
          dTextInput
          [name]="item.prop"
          [(ngModel)]="data.data_json[item.prop]"
          *ngIf="item.type === 'input'"
          [dValidateRules]="item.rule"
          [dValidateRules]="item.required ? item.rule : {}"
      />
      <textarea
          [name]="item.prop"
          [(ngModel)]="data.data_json[item.prop]"
          *ngIf="item.type === 'textarea'"
          [dValidateRules]="item.rule"
          [dValidateRules]="item.required ? item.rule : {}"
      ></textarea>
      <d-select
          *ngIf="item.type === 'select'"
          [appendToBody]="true"
          [options]="item.options"
          [name]="item.prop"
          [(ngModel)]="data.data_json[item.prop]"
          [dValidateRules]="item.required ? item.rule : []"
      ></d-select>
      <!-- <div
           class="devui-input-group devui-dropdown-origin"
           *ngIf="item.type === 'datePicker'"
	   >
           <input
           class="devui-input devui-form-control"
           placeholder="y/MM/dd"
           (click)="datePicker1.toggle()"
           [name]="item.prop"
           [(ngModel)]="data.data_json[item.prop]"
           autocomplete="off"
           dDatepicker
           [appendToBody]="true"
           #datePicker1="datepicker"
           [dValidateRules]="item.required ? item.rule : []"
           />
           <div
           *ngIf="selectedDate1"
           class="devui-input-group-addon close-icon-wrapper"
           (click)="datePicker1.clearAll()"
           >
           <i class="icon icon-close"></i>
           </div>
           <div class="devui-input-group-addon" (click)="datePicker1.toggle()">
           <i class="icon icon-calendar"></i>
           </div>
	   </div> -->
    </d-form-control>
  </d-form-item>
  <d-form-item>
    <d-form-label>
      是否立即执行:
    </d-form-label>
    <d-form-control extraInfo="选择表示放到执行队列,否则放到就绪队列,需要触发运行">
      <d-checkbox [label]="''" [isShowTitle]="false" (change)="onStatusChange($event)" [ngModel]="checked" name="check"></d-checkbox>
    </d-form-control>
  </d-form-item>
  <d-form-operation *ngIf="formConfig.showSubmit" class="da-form-operation">
    <d-button *ngIf="showYunxing" style="margin-right: 5px" dFormSubmit [dFormSubmitData]="'submit-button'">立即运行</d-button>
    <d-button *ngIf="!showYunxing" style="margin-right: 5px" dFormSubmit [dFormSubmitData]="'submit-button'">任务就绪</d-button>
    <d-button dFormReset bsStyle="common">重置</d-button>
  </d-form-operation>
</form>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { DialogService } from 'ng-devui';
import { Router } from '@angular/router';
import { FormConfig } from 'src/app/@shared/components/admin-form/admin-form.type';

import { PipelineService } from 'src/app/@core/services/pipeline.service';
import { Pipeline } from 'src/app/@shared/models/pipeline';

@Component({
    selector: 'app-pipeline-detail',
    templateUrl: './pipeline-detail.component.html',
    styleUrls: ['./pipeline-detail.component.css']
})
export class PipelineDetailComponent implements OnInit {

    busy?: Subscription;
    items: any[] = [];

    p_id: number = Number(this.route.snapshot.queryParamMap.get('id'));

    showYunxing: boolean = false;
    checked: boolean = false;

    formConfig: FormConfig = {
        labelSize: 'sm',
        items: this.items,
        showSubmit: true
    };
    // status -1 means that task will not run only if you have triggered.
    data: any = { "data_json": {}, "p_id": this.p_id, "result": "", "status": -1, "trigger": localStorage.getItem('display_name') };
    pipeline: Pipeline = {
        'id': 0,
        'name': '',
        'nickname': '',
        'p_creator': '',
        'p_tag': '',
        'description': '',
        'html_form_json': '',
        'status': 0,
        'create_timestamp': '',
        'update_timestamp': ''
    };

    constructor(
        private route: ActivatedRoute,
        private router: Router,
        private pipelineService: PipelineService,
        private dialogService: DialogService
    ) { }

    ngOnInit(): void {
        this.getPipeline();
    }
    private getPipeline() {
        this.pipelineService.getPipeline(this.p_id)
            .subscribe((res) => {
                console.log('res is ', res);
                this.pipeline = JSON.parse(JSON.stringify(res)).data || {};
                this.formConfig = JSON.parse(this.pipeline['html_form_json']);
                this.formConfig.showSubmit = true;
            });
    }

    submitForm(e: any) {
        if (this.checked) {
            this.data['status'] = 0;
        }

        console.log('form data is ', this.data);
        this.pipelineService.addPipelineTask(this.data)
            .subscribe((res: any) => {
                const pipeline_task = JSON.parse(JSON.stringify(res)).data || {};
                if (pipeline_task) {
                    this.router.navigateByUrl(`/pipeline/task?id=${pipeline_task.id}`);
                }
            });

    }

    onStatusChange(e: any) {
        this.checked = !this.checked;
        this.showYunxing = !this.showYunxing;
    }
}

总结

  • 界面相关

通过json_str字符串保存流水线的结构,表单,名称等,前端再次加载json_str实现

自定义表单设计和提交

  • 消息处理

通过流水线名称进行消息中转,处理完成进行流水线任务的评论处理等