Vue实现自定义流程图的创建(v1.1.0版——最终版本-数据分组展示,生成对象进行提交)_vue自定义流程图-程序员宅基地

技术标签: chrome  Vue  前端  vue.js  npm  javascript  

v0.1.1 - 基础版本

1、安装

这里用到的vue组件库是vue-dragging

$ npm install awe-dnd --save

2、代码

// main.js

import VueDND from 'awe-dnd'

Vue.use(VueDND)
// your.vue
<template>
  <div class="color-show">
    <div v-for="v in colors" v-dragging="{ list: colors, item: v, group: 'color' }" class="color-box" :style="{'background-color': v.text}" :key="v.id" >
      <input type="text"  :placeholder="v.text" :disabled="v.disabled" />
    </div>
    <button @click="addBox">新增</button>
  </div>
</template>

<script>
export default {
    
  data() {
    
    return {
    
      colors: [
        {
    
          text: "开始",
          id: 0,
          disabled: true
        },
        {
    
          text: "请输入内容",
          id: 1
        },
        {
    
          text: "结束",
          disabled: true,
          id: 999
        }
      ],
      colorShow: true,
      IsDisabled: true,
      id : 2,
    };
  },
  methods: {
    
    addBox(){
    
      this.colors.splice( length-1, 0, {
    text:"请输入内容", id: this.id} );
      this.id++;
    }
  }
};
</script>

<style>
.color-show {
    
  cursor: pointer;
  box-sizing: border-box;
  margin: 200px 0 0 200px;
  display: flex;
  flex-wrap: wrap;
  width: 100rem;
}
.color-box {
    
  border-radius: 20px;
  cursor: pointer;
  box-sizing: border-box;
  margin-left: 20px;
  margin-top: 20px;
  padding: 0;
  height: 6rem;
  background: skyblue;
  line-height: 6rem;
  text-align: center;
  transition: transform 0.3s;
}

input {
    
  cursor: pointer;
  box-sizing: border-box;
  outline-style: none;
  border: none;
  width: 100%;
  height: 100%;
  background-color: transparent;
  text-align: center;
  font-size: 18px;
  color: black;
}

button {
    
  width: 10%;
  font-size: 18px;
  color: black;
  height: 6rem;
  text-align: center;
  border-radius: 20px;
  cursor: pointer;
  margin-left: 20px;
  margin-top: 20px;
  border: none;
}

button:focus {
    
  outline: 0;
}
</style>

3、Git地址

https://github.com/hilongjw/vue-dragging.git

4、效果演示

在这里插入图片描述

v0.1.2 - 箭头版本

上面一个版本实现了基本的添加功能,但是可视化效果并不是太好,因此做了改进,增加了箭头,修改代码如下:

1、代码

<template>
  <div class="color-show">
    <div v-for="v in colors" v-dragging="{ list: colors, item: v, group: 'color' }" class="color-box" :style="{'background-color': v.text}" :key="v.id" >
      <input type="text"  :placeholder="v.text" :disabled="v.disabled" />
      <img class="jt" src="../assets/jt.jpg" />
    </div>
    <div class="last"><input type="text"  placeholder="结束" disabled /></div>
    <button @click="addBox">新增</button>
  </div>
</template>

<script>
export default {
    
  data() {
    
    return {
    
      colors: [
        {
    
          text: "开始",
          id: 0,
          disabled: true
        },
        {
    
          text: "请输入内容",
          id: 1
        }
      ],
      colorShow: true,
      IsDisabled: true,
      index : 2,
    };
  },
  methods: {
    
    addBox(){
    
      this.colors.splice( this.index, 0, {
    text:"请输入内容", id: this.index} );
      this.index++;
    }
  }
};
</script>

<style>
.color-show {
    
  cursor: pointer;
  box-sizing: border-box;
  margin: 200px 0 0 200px;
  display: flex;
  flex-wrap: wrap;
  width: 100rem;
}
.color-box {
    
  display: flex;
  cursor: pointer;
  box-sizing: border-box;
  margin-left: 20px;
  margin-top: 20px;
  padding: 0;
  height: 6rem;
  line-height: 6rem;
  text-align: center;
  transition: transform 0.3s;
}

input {
    
  flex: 1;
  cursor: pointer;
  box-sizing: border-box;
  outline-style: none;
  background: rgb(128, 190, 234);
  border-radius: 20px;
  border: none;
  width: 100%;
  height: 100%;
  text-align: center;
  font-size: 18px;
  color: black;
}

.last {
    
  cursor: pointer;
  box-sizing: border-box;
  margin-left: 20px;
  margin-top: 20px;
  padding: 0;
  height: 6rem;
  line-height: 6rem;
  text-align: center;
  transition: transform 0.3s;
}

button {
    
  width: 10%;
  font-size: 18px;
  color: black;
  height: 6rem;
  text-align: center;
  border-radius: 20px;
  cursor: pointer;
  margin-left: 20px;
  margin-top: 20px;
  border: none;
}

button:focus {
    
  outline: 0;
}

.jt {
    
  flex: 1;
  width: 223px;
  height: 96px;
  margin-left: 20px;
}

</style>

2、新增加的图片

在这里插入图片描述

3、修改部分

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.效果演示

在这里插入图片描述

v0.1.3 - 一行显示更多版本

1、代码

<style>
.color-show {
    
  cursor: pointer;
  box-sizing: border-box;
  margin: 200px 0 0 120px;
  display: flex;
  flex-wrap: wrap;
  width: 100rem;
}
.color-box {
    
  display: flex;
  cursor: pointer;
  box-sizing: border-box;
  margin-left: 10px;
  margin-top: 20px;
  padding: 0;
  width: 19%;
  height: 6rem;
  line-height: 6rem;
  text-align: center;
  transition: transform 0.3s;
}

input {
    
  flex: 1;
  cursor: pointer;
  box-sizing: border-box;
  outline-style: none;
  background: rgb(128, 190, 234);
  border-radius: 20px;
  border: none;
  width: 100%;
  height: 100%;
  text-align: center;
  font-size: 18px;
  color: black;
}

.last {
    
  cursor: pointer;
  box-sizing: border-box;
  margin-left: 10px;
  margin-top: 20px;
  padding: 0;
  width: 144px;
  height: 6rem;
  line-height: 6rem;
  text-align: center;
  transition: transform 0.3s;
}

button {
    
  width: 10%;
  font-size: 18px;
  color: black;
  height: 6rem;
  text-align: center;
  border-radius: 20px;
  cursor: pointer;
  margin-left: 10px;
  margin-top: 20px;
  border: none;
}

button:focus {
    
  outline: 0;
}

.jt {
    
  flex: 1;
  width: 140px;
  height: 96px;
  margin-left: 10px;
}

</style>

2、效果演示

在这里插入图片描述

v0.1.4 - 带删除功能版本

1、代码

<template>
  <div class="color-show">
    <div class="btn">
      <button @click="addBox">新增</button>
      <button @click="delBox">删除</button>
    </div>
    <div class="start">
      <input type="text"  placeholder="开始" disabled />
      <img class="jt" src="../assets/jt.jpg" />
    </div>
    <div v-for="v in colors" v-dragging="{ list: colors, item: v, group: 'color' }" class="color-box" :style="{'background-color': v.text}" :key="v.id">
      <input type="text" :placeholder="v.text" :disabled="v.disabled" />
      <img class="jt" src="../assets/jt.jpg" />
    </div>
    <div class="last"><input type="text"  placeholder="结束" disabled /></div>
  </div>
</template>

<script>
export default {
    
  data() {
    
    return {
    
      colors: [
        {
    
          text: "请输入内容",
          id: 0
        }
      ],
      index : 1,
      closeShow: false
    };
  },
  methods: {
    
    addBox(){
    
      this.colors.splice( this.index, 0, {
    text:"请输入内容", id: this.index} );
      this.index++;
    },
    delBox(){
    
      this.colors.splice( this.index-1, 1);
      this.index--;
    }
  }
};
</script>

<style>
.color-show {
    
  cursor: pointer;
  box-sizing: border-box;
  margin: 200px 0 0 120px;
  display: flex;
  flex-wrap: wrap;
  width: 100rem;
}

.btn {
    
  display: flex;
  width: 18%;
  position: absolute;
  top: 130px;
  left: 50%;
  transform: translate(-50%, -50%);
}

.color-box {
    
  position: relative;
  display: flex;
  cursor: pointer;
  box-sizing: border-box;
  margin-left: 10px;
  margin-top: 20px;
  padding: 0;
  width: 19%;
  height: 6rem;
  line-height: 6rem;
  text-align: center;
  transition: transform 0.3s;
}

input {
    
  flex: 1;
  cursor: pointer;
  box-sizing: border-box;
  outline-style: none;
  background: rgb(128, 190, 234);
  border-radius: 20px;
  border: none;
  width: 100%;
  height: 100%;
  text-align: center;
  font-size: 18px;
  color: black;
}

.start, .last {
    
  display: flex;
  cursor: pointer;
  box-sizing: border-box;
  margin-left: 10px;
  margin-right: 150px;
  margin-top: 20px;
  padding: 0;
  width: 144px;
  height: 6rem;
  line-height: 6rem;
  text-align: center;
  transition: transform 0.3s;
}

.start input {
    
  width: 144px;
}

.last {
    
  margin-right: 10px;
}

button {
    
  flex: 1;
  width: 10%;
  font-size: 18px;
  color: black;
  height: 6rem;
  text-align: center;
  border-radius: 20px;
  cursor: pointer;
  margin-left: 20px;
  border: none;
}

button:focus {
    
  outline: 0;
}

.jt {
    
  flex: 1;
  width: 140px;
  height: 96px;
  margin-left: 10px;
}

</style>

2、效果演示

在这里插入图片描述

v0.2.1版 - 修改使用的插件库,优化操作和界面

1、安装

npm i vuedraggable -s

2、代码

<template>
  <div class="stepsBox">
    <div class="start-steps">
      <button class="start-btn">开始</button>
    </div>
    <div class="other-steps">
      <div class="drap-box">
        <vuedraggable class="draggable">
          <div class="steps-box" v-for="(i, v) in stepsBox" :key="i">
            <div class="steps-btn">
              <input type="text" maxlength="30" placeholder="请输入阶段名称">
            </div>
            <div class="stepsAdd stepsAdd-before" @click="addStepBox1(i, v)">+</div>
            <div class="stepsAdd stepsAdd-after" @click="addStepBox2(i, v)">+</div>
            <div class="sb-close" @click="subStepBox(i, v)">-</div>
          </div>
          <div class="end-steps">
            <button class="end-btn">结束</button>
            <div class="stepsAdd stepsAdd-end" @click="addStepBox1()">+</div>
          </div>
        </vuedraggable>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import {
     Vue, Component } from 'vue-property-decorator';
import vuedraggable from 'vuedraggable';

@Component({
    
  components: {
     vuedraggable }
})
export default class StepDemo extends Vue {
    
  private stepsBox: any = [];
  private id: any = 1;
  private addStepBox1(v: any, i: number): void {
    
    this.id++;
    this.stepsBox.splice(i, 0, this.id);
  }
  private addStepBox2(v: any, i: number): void {
    
    this.id++;
    this.stepsBox.splice(i+1,0,this.id);
  }
  private subStepBox(v: any, i: number): void {
    
    this.stepsBox.splice( i, 1 );
  }

}
</script>

<style lang="less" scoped>
i {
    
  font-style: normal;
}

div {
    
  box-sizing: border-box;
}

.stepsBox {
    
  position: relative;
  display: flex;
  flex-wrap: nowrap;

  .draggable {
    
    display: flex;
    flex-wrap: wrap;
  }

  .stepsAdd {
    
      text-align: center;
      position: absolute;
      top: 50%;
      border-radius: 100%;
      width: 20px;
      height: 20px;
      line-height: 18px;
      margin-top: -9px;
      background-color: #409eff;
      color: #fff;
      z-index: 1;
      cursor: pointer;
    }

  .start-steps,
  .end-steps {
    
    height: 70px;
    width: 120px;
    position: relative;
    padding: 15px 30px 15px 0;  
  }

  .end-steps {
    
    box-sizing: border-box;
    position: relative;
    padding: 15px 0 15px 30px;

    .stepsAdd {
    
      left: -10px;
    }
  }

  .end-steps::before {
    
    content: "";
    position: absolute;
    top: 50%;
    left: -30px;
    width: 60px;
    height: 1px;
    background: #c0c4cc;
  }

  .end-steps::after {
    
    position: absolute;
    content: "";
    width: 0;
    height: 0;
    border-width: 5px;
    border-style: dashed solid;
    top: 50%;
    left: 25px;
    margin-top: -4px;
    border-color: transparent transparent transparent #c0c4cc;
  }

  .other-steps {
    
    position: relative;
    display: flex;
    flex-wrap: wrap;

    .steps-box {
    
      text-align: center;
      color: #333;
      font-size: 12px;
      cursor: pointer;
      padding: 10px 30px;
      line-height: 50px;
      position: relative;
    }

    .steps-box::before {
    
      content: "";
      position: absolute;
      top: 50%;
      left: -30px;
      width: 60px;
      height: 1px;
      background: #c0c4cc;
    }


    .steps-btn {
    
      box-sizing: border-box;
      position: relative;
      border-radius: 4px;
      border: 1px solid #409eff;
      background: #409eff;

      input {
    
        text-align: center;
        width: 100px;
        border: none;
        outline: 0;
        padding: 0 5px;
        font-size: 14px;
        font-weight: 500px;
        line-height: 48px;
        background: #409eff;
        color: #fff;
      }
    }

    .steps-btn::before {
    
      position: absolute;
        content: "";
        width: 0;
        height: 0;
        border-width: 5px;
        border-style: dashed solid;
        top: 50%;
        left: -5px;
        margin-top: -5px;
        border-color: transparent transparent transparent #c0c4cc;
    }
  }

  .drap-box {
    
    display: flex;
    flex-wrap: wrap;
  }

  .stepsAdd-before {
    
    // display: none;
    left: -10px;
    z-index: 2;
  }

  .stepsAdd-end {
    
    display: block;
  }

  .stepsAdd-after {
    
    // display: none;
    right: -10px;
    z-index: 2;
  }

  .sb-close {
    
    display: none;
    width: 16px;
    height: 16px;
    border-radius: 16px;
    color: #fff;
    text-align: center;
    position: absolute;
    color: #fff;
    background: #f56c6c;
    font-size: 16px;
    border-radius: 50%;
    top: 3px;
    right: 23px;
    line-height: 12px;
  }

  .end-steps:hover {
    
    .stepsAdd-after {
    
      display: block;
    }
  }

  .steps-box:hover {
    
    .stepsAdd-before {
    
      display: block;
    }

    .stepsAdd-after {
    
      display: block;
    }

    .sb-close {
    
      display: block;
    }
  }

  .start-btn,
  .end-btn {
    
    width: 90px;
    height: 40px;
    border: 1px solid #b3d8ff;
    border-radius: 20px;
    text-align: center;
    color: #409eff;
    line-height: 40px;
    font-size: 12px;
    cursor: pointer;
    background: #ecf5ff;
  }
}
</style>

3、效果演示

可以在任意地方添加流程模块

在这里插入图片描述

可以删除指定的流程模块

在这里插入图片描述

选择了新的组件库vuedraggable

在这里插入图片描述

v0.2.2版 - 新增提交功能,可把添加的数据生成提交到后端

1、代码

<div class="selectSteps" v-if="showSelect">
	<el-button type="success" size="medium" style="margin-left:50px; padding:10px 30px; font-size:14px;" @click="click">提交</el-button>
	<input style="margin-left:50px; height:28px; text-align:center;" v-model="confirmMessage" disabled />
</div>
private showSelect: boolean = false;
private showEndSteps: boolean = true;
private confirmMessage: string = '提交的信息';
private addStepBox1(v: any, i: number): void {
    
    this.id++;
    this.stepsBox.splice(i, 0, this.id);
    if(this.stepsBox.length !== 0) {
    
      this.showSelect = true;
      this.showEndSteps = false;
    };
  }
  private addStepBox2(v: any, i: number): void {
    
    this.id++;
    this.stepsBox.splice(i + 1, 0, this.id);    
  }
  private subStepBox(v: any, i: number): void {
    
    this.stepsBox.splice(i, 1);
    if(this.stepsBox.length === 0) {
    
      this.showSelect = false;
      this.showEndSteps = true;
    };
  }

  private click(): void {
    
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll('input');
    for(let i=0; i<stepsArrey.length-2; i++) {
    
      stepsMessage.push(stepsArrey[i].value);
    };
    this.confirmMessage = stepsMessage.join('-');
  }

2、效果演示

在这里插入图片描述

v0.2.3版 - 新增选择功能,限定用户输入条件

第一版:侧面打开进行选择

该版本写了两版,功能大致相同,样式上一个版本有,也没做过多的改动,就不放了

1、代码
<template>
  <div class="main">
    <div class="stepsBox">
      <div class="start-steps">
        <button class="start-btn">开始</button>
      </div>
      <div class="other-steps">
        <div class="drap-box">
          <vuedraggable v-model="stepsBox" class="draggable">
            <div class="steps-box" v-for="(i, v) in stepsBox" :key="i">
              <div class="steps-btn">
                <input type="text" maxlength="30" placeholder="点击进行选择" @click="showDrawer(i, v)" value="" />
              </div>
              <div class="stepsAdd stepsAdd-before" @click="addStepBox1(i, v)">+</div>
              <div class="stepsAdd stepsAdd-after" @click="addStepBox2(i, v)">+</div>
              <div class="sb-close" @click="subStepBox(i, v)">-</div>
            </div>
            <div class="end-steps">
              <button class="end-btn">结束</button>
              <div class="stepsAdd stepsAdd-end" v-if="showEndSteps" @click="addStepBox1()">+</div>
            </div>
          </vuedraggable>
        </div>
      </div>
      <el-drawer title="选择栏" :visible.sync="drawer" :with-header="false" size="15%" style="text-align: center;" @open="openDrawer" @close="closeDrawer">
        <template>
          <el-select class="selectBox" v-model="selectValue" placeholder="请选择" @change="selectChange">
            <el-option v-for="i in options" :key="i.label" :label="i.label" :value="i.value" />
          </el-select>
        </template>
      </el-drawer>
    </div>
    <div class="confirm-box" v-if="showConfirm">
      <el-button type="success" size="medium" style="padding:10px 30px; font-size:14px;" @click="confirm">提交</el-button>
      <input style="margin-left:50px; height:28px; text-align:center;" :size="iptWidth" v-model="confirmMessage" disabled />
    </div>
  </div>
</template>

<script lang="ts">
import {
     Vue, Component } from "vue-property-decorator";
import vuedraggable from "vuedraggable";

@Component({
    
  components: {
     vuedraggable }
})
export default class StepDemo extends Vue {
    
  private stepsBox: any = [];
  private id: any = 0;
  private selectId: any = 0;
  private drawer: boolean = false;
  private selectValue: any = '请选择';
  private showEndSteps: boolean = true;
  private showConfirm: boolean = false;
  private index: any = '';
  private confirmMessage: string = "提交的信息";
  private options: any[] = [
    {
     value: 'DI部署', label: 'DI部署' },
    {
     value: 'DI验证', label: 'DI验证' },
    {
     value: 'ST部署', label: 'ST部署' },
    {
     value: 'ST验证', label: 'ST验证' },
    {
     value: '同步生产', label: '同步生产' },
    {
     value: '生产部署', label: '生产部署' },
    {
     value: '生产验证', label: '生产验证' },
  ];
  private selVal: any = '';
  private iptWidth: any = '';

  private showDrawer(v: any, i: number): void {
    
    this.drawer = true;
    this.index = i;
  }

  private selectChange(selVal: any): void {
    
    let stepsArrey = document.querySelectorAll("input");  
    stepsArrey[this.index].value = selVal;
    this.selVal = selVal;
  }

  private openDrawer(): void {
    
    let stepsArrey = document.querySelectorAll("input");  
    this.selectValue = stepsArrey[this.index].value;
  }

  private closeDrawer():void {
    
    this.selectValue = '请选择';
  }

  private addStepBox1(v: any, i: number): void {
    
    this.id++;
    this.selectId++;
    this.stepsBox.splice(i, 0, this.id);
    if (this.stepsBox.length !== 0) {
    
      this.showConfirm = true;
      this.showEndSteps = false;
    }
  }
  private addStepBox2(v: any, i: number): void {
    
    this.id++;
    this.selectId++;
    this.stepsBox.splice(i + 1, 0, this.id);
  }
  private subStepBox(v: any, i: number): void {
    
    this.stepsBox.splice(i, 1);
    if (this.stepsBox.length === 0) {
    
      this.showConfirm = false;
      this.showEndSteps = true;
    }
  }

  private confirm(): void {
    
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll("input");
    for (let i = 0; i < stepsArrey.length - 2; i++) {
    
      stepsMessage.push(stepsArrey[i].value);
    }
    this.confirmMessage = stepsMessage.join("-");
    this.iptWidth = 1.8 * this.confirmMessage.length;
  }

}
</script>

2、效果演示

在这里插入图片描述

第二版:下方展示进行选择

1、代码
<template>
  <div class="main">
    <div class="stepsBox">
      <div class="start-steps">
        <button class="start-btn">开始</button>
      </div>
      <div class="other-steps">
        <div class="drap-box">
          <vuedraggable v-model="stepsBox" class="draggable">
            <div class="steps-box" v-for="(i, v) in stepsBox" :key="i">
              <div class="steps-btn">
                <input type="text" maxlength="30" placeholder="点击进行选择" value="" @focus="iptFocus(v, i)" @blur="iptBlur(v, i)" />
              </div>
              <div class="stepsAdd stepsAdd-before" @click="addStepBox1(i, v)">+</div>
              <div class="stepsAdd stepsAdd-after" @click="addStepBox2(i, v)">+</div>
              <div class="sb-close" @click="subStepBox(i, v)">-</div>
            </div>
            <div class="end-steps">
              <button class="end-btn">结束</button>
              <div class="stepsAdd stepsAdd-end" v-if="showEndSteps" @click="addStepBox1()">+</div>
            </div>
          </vuedraggable>
        </div>
      </div>
    </div>
    <div class="select-box" v-if="showSelect">
      <template>
          <el-select class="selectBox" v-model="selectValue" placeholder="请选择" @change="selectChange">
            <el-option v-for="i in options" :key="i.label" :label="i.label" :value="i.value" />
          </el-select>
        </template>
    </div>
    <div class="confirm-box" v-if="showConfirm">
      <el-button type="success" size="medium" style="padding:10px 30px; font-size:14px;" @click="confirm">提交</el-button>
      <input style="margin-left:50px; height:28px; text-align:center;" :size="iptWidth" v-model="confirmMessage" disabled />
    </div>
  </div>
</template>

<script lang="ts">
import {
     Vue, Component } from "vue-property-decorator";
import vuedraggable from "vuedraggable";

@Component({
    
  components: {
     vuedraggable }
})
export default class StepDemo extends Vue {
    
  private stepsBox: any = [];
  private id: any = 0;
  private selectId: any = 0;
  private drawer: boolean = false;
  private selectValue: any = '';
  private showEndSteps: boolean = true;
  private showSelect: boolean = false;
  private showConfirm: boolean = false;
  private index: any = '';
  private confirmMessage: string = "提交的信息";
  private options: any[] = [
    {
     value: 'DI部署', label: 'DI部署' },
    {
     value: 'DI验证', label: 'DI验证' },
    {
     value: 'ST部署', label: 'ST部署' },
    {
     value: 'ST验证', label: 'ST验证' },
    {
     value: '同步生产', label: '同步生产' },
    {
     value: '生产部署', label: '生产部署' },
    {
     value: '生产验证', label: '生产验证' },
  ];
  private selVal: any = '';
  private iptWidth: any = '';

  private iptFocus(i: any): void {
    
    let stepsArrey = document.querySelectorAll("input");
    this.index = i;
    this.selectValue = stepsArrey[this.index].value;
  }

  private selectChange(selVal: any): void {
    
    let stepsArrey = document.querySelectorAll("input");  
    stepsArrey[this.index].value = selVal;
    this.selVal = selVal;
  }

  private iptBlur(i: any): void {
    
    let stepsArrey = document.querySelectorAll("input");
    this.index = i;
  }

  private addStepBox1(v: any, i: number): void {
    
    this.id++;
    this.selectId++;
    this.stepsBox.splice(i, 0, this.id);
    this.selectValue = '';
    if (this.stepsBox.length !== 0) {
    
      this.showSelect = true;
      this.showConfirm = true;
      this.showEndSteps = false;
    }
  }
  private addStepBox2(v: any, i: number): void {
    
    this.id++;
    this.selectId++;
    this.stepsBox.splice(i + 1, 0, this.id);
    this.selectValue = '';
  }
  private subStepBox(v: any, i: number): void {
    
    this.stepsBox.splice(i, 1);
    if (this.stepsBox.length === 0) {
    
      this.showConfirm = false;
      this.showEndSteps = true;
      this.showSelect = false;
    }
  }

  private confirm(): void {
    
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll("input");
    for (let i = 0; i < stepsArrey.length - 2; i++) {
    
      stepsMessage.push(stepsArrey[i].value);
    }
    this.confirmMessage = stepsMessage.join("-");
    this.iptWidth = 1.8 * this.confirmMessage.length;
  }

}
</script>
2、效果演示

在这里插入图片描述

v0.2.4版 - 优化可视化效果

1、代码

private iptFocus(i: any): void {
    
    let stepsArrey = document.querySelectorAll("input");
    this.index = i;
    this.selectValue = stepsArrey[this.index].value;
    for(let i=0; i<stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
    stepsArrey[this.index].style.backgroundColor = '#409eff';
    stepsArrey[this.index].style.color = '#fff';
  }

private addStepBox1(v: any, i: number): void {
    
    let stepsArrey = document.getElementsByTagName("input");
    if(i) {
    
      window.setTimeout(()=>{
    stepsArrey[i].focus()},0);
    } else {
    
      window.setTimeout(()=>{
    stepsArrey[0].focus()},0);
    };
    this.id++;
    this.selectId++;
    this.stepsBox.splice(i, 0, this.id);
    this.selectValue = '';
    if (this.stepsBox.length !== 0) {
    
      this.showSelect = true;
      this.showConfirm = true;
      this.showEndSteps = false;
    }
  }

  private addStepBox2(v: any, i: number): void {
    
    if(i >= 0) {
    
      let stepsArrey = document.getElementsByTagName("input");
      i = i + 1;
      window.setTimeout(()=>{
    stepsArrey[i].focus()},0);
    }
    this.id++;
    this.selectId++;
    this.stepsBox.splice(i + 1, 0, this.id);
    this.selectValue = '';
  }

2、原理及注意点

这里用的DOM获取页面节点,因为用ref会导致$refs报错,可以获取到DOM元素,但是就是取不到值,在之前提交的时候也是一样

3、效果演示

在这里插入图片描述

v0.2.5版 - 优化提交后背景色显示问题

1、代码

private confirm(): void {
    
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll("input");
    for (let i = 0; i < stepsArrey.length - 2; i++) {
    
      stepsMessage.push(stepsArrey[i].value);
    }
    this.confirmMessage = stepsMessage.join("-");
    this.iptWidth = 1.8 * this.confirmMessage.length;
    for(let i = 0; i < stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
  }

2、效果演示

在这里插入图片描述

v0.2.6版 - 优化删除模块后选择框显示问题以及模块背景色问题,限制用户只能从选择框中进行步骤选择

1、存在问题

在这里插入图片描述

2、代码

<input type="text" maxlength="30" placeholder="点击进行选择" value="" @focus="iptFocus(v, i)" @blur="iptBlur(v, i)" autofocus readonly />
// autofocus:新增是自动获取焦点
// readonly:input为只读
private subStepBox(v: any, i: number): void {
    
    this.stepsBox.splice(i, 1);
    if (this.stepsBox.length === 0) {
    
      this.showConfirm = false;
      this.showEndSteps = true;
      this.showSelect = false;
    };
    this.selectValue = '请选择修改模块';
    let stepsArrey = document.querySelectorAll("input");
    for(let i = 0; i < stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
  }

3、效果演示

在这里插入图片描述
这里还存在一点点小的问题,后续版本再做修复。

v0.2.7版 - 优化提交时有空白项的提醒和清除空白项提交

1、存在问题

在这里插入图片描述
在有空白选项时,提交就会出现错误,导致提交的信息有误。
这里做的优化时允许用户提交,但是会清除空白选项。

2、代码

  private confirm(): void {
    
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll('input');
    for(let i = 0; i < stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
    + for (let i = 0; i < stepsArrey.length - 2; i++) {
    
      + if(stepsArrey[i].value == '') {
    
        + stepsArrey[i].style.backgroundColor = '#EE1111';
        + stepsArrey[i].style.color = '#fff';
      + };
      stepsMessage.push(stepsArrey[i].value);
    };
    + stepsMessage = stepsMessage.filter( s => {
     return s && s.trim() }); // 去除空白的无效项
    this.confirmMessage = stepsMessage.join('-');
    this.iptWidth = 1.8 * this.confirmMessage.length;
  }

3、效果演示

在这里插入图片描述

v0.2.8版 - 阻止了用户有空白块的提交行为

1、存在问题

在上一个版本中,可以看到用户及时在有空白快的时候也可以提交,对于提交的校验效果不好,因此这里的功能改成了在点击提交之后,提示用户没有填写的空白项,并阻止用户的提交行为。

2、代码

  private confirm(): void {
    
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll('input');
    for(let i = 0; i < stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
    for (let i = 0; i < stepsArrey.length - 2; i++) {
    
      if(stepsArrey[i].value != '') {
    
        stepsMessage.push(stepsArrey[i].value);
      } else {
    
        for (let i = 0; i < stepsArrey.length - 2; i++) {
    
          if(stepsArrey[i].value === '') {
    
            stepsArrey[i].style.backgroundColor = '#EE1111';
            stepsArrey[i].style.color = '#fff';
          };
        }
        this.$message({
    type: 'error', message: '请填写完整的流程'});
        return;
      }
    };
    this.confirmMessage = stepsMessage.join('-');
    this.iptWidth = 1.8 * this.confirmMessage.length;
  }

3、效果演示

在这里插入图片描述

v1.0.0版 - 重新构建数据,以数组形式保存

1、之前存在问题

存储值的时候是1234这样的id值,二无法与value值对应,本次改动将list定义为数组,将每一个块里的数据以对象形式存储,这样即使从后端获取到数据,也可以直接渲染。并新增加了重置按钮,效果跟之前版本的效果相同。

2、代码

<template>
  <div class="row">
    <div class="step_box">
      <div class='start-steps'>
        <button class='start-btn'>开始</button>
      </div>
      <draggable :list="list" disabled class="list-group" ghost-class="ghost" @start="dragging = true" @end="dragging = false">
        <div class="step" v-for="(v, i) in list" :key="v.id">
          <textarea class="list-group-item" placeholder="请选择流程" maxlength='30' type="text" autofocus readonly @focus='iptFocus(v, i)' @blur='iptBlur(v, i)' :value='v.name' />
          <div class='stepsAdd stepsAdd-before' @click='addBefore(i)'>+</div>
          <div class='stepsAdd stepsAdd-after' @click='addAfter(i)'>+</div>
          <div class='sb-close' @click='deleteStep(i)'>-</div>
        </div>
        <div class='end-steps'>
          <button class='end-btn'>结束</button>
          <div class='stepsAdd stepsAdd-end' v-if='showEndSteps' @click='addBefore()'>+</div>
        </div>
      </draggable>
    </div>
    <div class='select-box'>
      <template>
          <el-select class='selectBox' v-model='selectValue' placeholder='请选择步骤' @change='selectChange'>
            <el-option v-for='i in options' :key='i.label' :label='i.label' :value='i.value' />
          </el-select>
        </template>
    </div>
    <div class='confirm-box'>
      <el-button type='success' size='medium' style='padding:8px 18px; font-size:14px;' @click="confirm">提交</el-button>
      <el-button type='success' size='medium' style='padding:8px 18px; margin-left:20px; font-size:14px;' @click="replace">重置</el-button>
      <input style='margin-left:20px; height:28px; text-align:center; border:1px solid #DCDFE6; border-radius:4px;' :size='iptWidth' v-model='confirmMessage' disabled />
    </div>
    
  </div>
</template>

<script lang='ts'>
import {
     Vue, Component, Prop } from 'vue-property-decorator';
import draggable from 'vuedraggable';

@Component({
    
  components: {
     draggable }
})
export default class StepDemo extends Vue {
    
  private confirmMessage: string = '提交的信息';
  private iptWidth: any = '';
  private id: any = 0;
  private showEndSteps: boolean = true;
  private dragging: boolean = false;
  private list: any = [];
  private options: any = [
    {
     value: 'DI部署', label: 'DI部署' },
    {
     value: 'DI验证', label: 'DI验证' },
    {
     value: 'ST部署', label: 'ST部署' },
    {
     value: 'ST验证', label: 'ST验证' },
    {
     value: '同步生产', label: '同步生产' },
    {
     value: '生产部署', label: '生产部署' },
    {
     value: '生产验证', label: '生产验证' }
  ];
  private index: any = '';
  private selVal: any = '';
  private selectValue: any = '';
  private addBefore(i: any): void{
    
    this.list.splice(i, 0, {
     name: "", id: this.id++ });
    if (this.list.length !== 0) {
    
      this.showEndSteps = false;
    };
    this.selectValue = '';
    let stepsArrey = document.getElementsByTagName('textarea');
    if(i) {
     window.setTimeout(() => {
     stepsArrey[i].focus()}, 0)}
    else {
     window.setTimeout(() => {
     stepsArrey[0].focus()}, 0)};
  }
  private addAfter(i: any): void{
    
    if(i >= 0) {
    
      let stepsArrey = document.getElementsByTagName('textarea');
      i = i + 1;
      window.setTimeout(() => {
     stepsArrey[i].focus(); }, 0);
    };
    this.list.splice(i + 1, 0, {
     name: "", id: this.id++ });
    this.selectValue = '';
  }
  private deleteStep(i: any): void {
    
    this.list.splice(i, 1);
    if (this.list.length === 0) {
    
      this.showEndSteps = true;
    };
    let stepsArrey = document.querySelectorAll('textarea');
    for(let i = 0; i < stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
  }
  private iptFocus(v: any, i: any): void {
    
    let stepsArrey = document.querySelectorAll('textarea');
    this.index = i;
    this.selectValue = stepsArrey[this.index].value;
    for(let i=0; i<stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
    stepsArrey[this.index].style.backgroundColor = '#409eff';
    stepsArrey[this.index].style.color = '#fff';
  }
  private iptBlur(v: any, i: any): void {
    
    this.index = i;
  }
  private selectChange(selVal: any): void {
    
    this.list[this.index].name = selVal;
    this.selVal = selVal;
  }
  private confirm(): void {
    
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll('textarea');
    for(let i = 0; i < stepsArrey.length; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
    for (let i = 0; i < stepsArrey.length; i++) {
    
      if(stepsArrey[i].value != '') {
    
        stepsMessage.push(stepsArrey[i].value);
      } else {
    
        for (let i = 0; i < stepsArrey.length; i++) {
    
          if(stepsArrey[i].value === '') {
    
            stepsArrey[i].style.backgroundColor = '#EE1111';
            stepsArrey[i].style.color = '#fff';
          };
        }
        this.$message({
    type: 'error', message: '请填写完整的流程'});
        return;
      }
    };
    this.confirmMessage = stepsMessage.join('-');
    this.iptWidth = 1.8 * this.confirmMessage.length;
  }
  private replace(): void{
    
    this.list = [];
    this.selectValue = '';
    this.confirmMessage = '提交的信息';
  }
}
</script>
<style lang="less" scoped>
.step_box {
    
  display: flex;
  flex-wrap: wrap;

  .start-steps,
  .end-steps {
    
    width: 120px;
    position: relative;
    padding: 15px 0;
  }
  .end-steps {
    
    padding: 15px 30px;
    .stepsAdd {
    
      left: -10px;
    }
  }
  .start-btn,
  .end-btn {
    
    width: 90px;
    height: 40px;
    border: 1px solid #b3d8ff;
    border-radius: 20px;
    text-align: center;
    color: #409eff;
    line-height: 40px;
    font-size: 12px;
    cursor: pointer;
    background: #ecf5ff;
  }
}
textarea {
    
  resize:none;
  outline: 0;
  font-size: 12px;
  caret-color: transparent;
}
textarea::-webkit-input-placeholder {
    
  color: #ccc;
}
.selectBox {
    
  margin: 20px 0 30px;
}
.end-steps::before {
    
  content: '';
  position: absolute;
  top: 50%;
  left: -30px;
  width: 60px;
  height: 1px;
  background: #c0c4cc;
}
.end-steps::after {
    
  position: absolute;
  content: '';
  width: 0;
  height: 0;
  border-width: 5px;
  border-style: dashed solid;
  top: 50%;
  left: 25px;
  margin-top: -4px;
  border-color: transparent transparent transparent #c0c4cc;
}
.stepsAdd-before {
    
  display: none;
  left: -10px;
  z-index: 2;
}
.stepsAdd {
    
  font-size: 14px;
  text-align: center;
  position: absolute;
  top: 50%;
  border-radius: 100%;
  width: 20px;
  height: 20px;
  line-height: 18px;
  margin-top: -10px;
  background-color: #409eff;
  color: #fff;
  z-index: 1;
  cursor: pointer;
}
.stepsAdd-end {
    
  display: block;
}
.stepsAdd-after {
    
  display: none;
  right: -10px;
  z-index: 2;
}
.end-steps:hover {
    
.stepsAdd-after {
    
  display: block;
  }
}
.step:hover {
    
  .stepsAdd-before {
    
    display: block;
  }
  .stepsAdd-after {
    
    display: block;
  }
  .sb-close {
    
    display: block;
  }
}
.sb-close {
    
  cursor: default;
  display: none;
  width: 16px;
  height: 16px;
  border-radius: 16px;
  color: #fff;
  text-align: center;
  position: absolute;
  color: #fff;
  background: #f56c6c;
  font-size: 16px;
  border-radius: 50%;
  top: 3px;
  right: 23px;
  line-height: 12px;
}
.buttons {
    
  margin-top: 35px;
}
.ghost {
    
  opacity: 0.5;
  background: #c8ebfb;
}
.list-group {
    
  display: flex;
  flex-wrap: wrap;
}
.step::before {
    
  content: '';
  position: absolute;
  top: 50%;
  left: -30px;
  width: 60px;
  height: 1px;
  background: #c0c4cc;
}
.step {
    
  position: relative;
  padding: 10px 30px;
}
.step::after {
    
  position: absolute;
  content: '';
  width: 0;
  height: 0;
  border-width: 5px;
  border-style: dashed solid;
  top: 50%;
  left: 25px;
  margin-top: -4px;
  border-color: transparent transparent transparent #c0c4cc;
}
.list-group-item {
    
  position: relative;
  width: 110px;
  box-sizing: border-box;
  border-radius: 4px;
  border: 1px solid #409eff;
  height: 48px;
  overflow: hidden;
  cursor: pointer;
  text-align: center;
  padding: 0 5px;
  font-size: 12px;
  line-height: 48px;
  background: #ecf5ff;
  color: #409eff;
}
</style>

3、效果演示

在这里插入图片描述

v1.1.0版 - 数据分组展示,生成对象进行提交

1、优化

新增了每个步骤的详情编辑

2、代码

<template>
  <div class="template_box">
    <div class="template_in">
      <h1>新增流程模板</h1>
      <div class="templateInfo">
          <el-form label-width="100px" :model="templateForm" ref="templateForm" :rules="templateRules">
            <el-form-item label="模板名称:" prop="name">
              <el-input v-model="templateForm.name" placeholder='请输入模板名称' />
            </el-form-item>
            <el-form-item label="模板说明:" prop="msg">
              <el-input type="textarea" :autosize="{ minRows: 3, maxRows: 4}" v-model="templateForm.msg" placeholder='请输入模板说明' />
            </el-form-item>
          </el-form>
      </div>
      <div class="step_box">
          <div class='start-steps'>
            <button class='start-btn'>开始</button>
          </div>
          <draggable :list="list" disabled class="list-group" ghost-class="ghost" @start="dragging = true" @end="dragging = false" filter=".undraggable">
            <div class="step" v-for="(v, i) in list" :key="v.id">
              <textarea class="list-group-item" placeholder="请选择流程" maxlength='30' autofocus readonly="readonly" @focus='iptFocus(v, i)' @blur='iptBlur(v, i)' :value='v.step_name' />
              <div class='stepsAdd stepsAdd-before' @click='addBefore(i)'>+</div>
              <div class='stepsAdd stepsAdd-after' @click='addAfter(i)'>+</div>
              <div class='sb-close' @click='deleteStep(i)'>-</div>
            </div>
            <div class='end-steps undraggable'>
              <button class='end-btn'>结束</button>
              <div class='stepsAdd stepsAdd-end' v-if='showEndSteps' @click='addBefore()'>+</div>
            </div>
          </draggable>
      </div>
      <div class="stepInfo">
          <p>步骤详情(请点击上方加号添加步骤)</p>
          <div class="stepDetails">
            <el-form ref="stepForm" label-width="100px" :model="stepForm" :rules="stepRules">
              <el-form-item label="步骤名称:" prop="step_name">
                <el-input v-model="stepForm.step_name" @change='stepnameChange' :disabled="templateAddDisable" placeholder='请输入步骤名称' />
              </el-form-item>
              <el-form-item label="步骤类型:" prop="step_type">
                <el-select class='typeBox' v-model='stepForm.step_type' placeholder='请选择类型' style="width: 500px;" @change='steptypeChange' :disabled="templateAddDisable">
                  <el-option v-for='i in typeItem' :key='i.id' :label='i.label' :value='i.value' />
                </el-select>
              </el-form-item>
              <el-form-item label="步骤功能:" prop="step_func">
                <el-select class='typeBox' v-model='stepForm.step_func' placeholder='请选择功能' style="width: 500px;" @change='featureChange' :disabled="templateAddDisable">
                  <el-option v-for='i in featureItem' :key='i.id' :label='i.label' :value='i.value' />
                </el-select>
              </el-form-item>
              <el-form-item label="URL地址:" prop="step_url">
                <el-input v-model="stepForm.step_url" @change='urlChange' :disabled="templateAddDisable" placeholder='请输入Url地址' />
              </el-form-item>
              <el-form-item label="备注:" prop="step_msg">
                <el-input type="textarea" v-model="stepForm.step_msg" :autosize="{ minRows: 3, maxRows: 4}" @change='remarksChange' :disabled="templateAddDisable" placeholder='请输入备注'  />
              </el-form-item>
            </el-form>
            </div>
      </div>
      <div class='confirmBox'>
          <el-button size='medium' style='padding:8px 18px; font-size:14px;' @click="closeDialog">返回</el-button>
          <el-button type='primary' size='medium' style='padding:8px 18px; margin-left:20px; font-size:14px;' @click="replace">重置</el-button>
          <el-button type='success' size='medium' style='padding:8px 18px; margin-left:20px; font-size:14px;' @click="confirm">提交</el-button>
      </div>
    </div>
  </div>
</template>

<script lang='ts'>
import {
     Vue, Component, Ref, Prop, Emit } from 'vue-property-decorator';
import draggable from 'vuedraggable';

@Component({
    
  components: {
     draggable }
})
export default class templateAdd extends Vue {
    
  @Ref() formRef!: any;
  private id: any = 0;
  private showEndSteps: boolean = true;
  private dragging: boolean = false;
  private list: any = [];
  private templateAddDisable: boolean = true;

  private typeItem: any = [
    {
     id: '1', label: '接口触发', value: 'api' },
    {
     id: '2', label: '人工流转', value: 'manual' }
  ]
  private featureItem: any = [
    {
     id: '1', label: 'Jenkins构建', value: 'build' },
    {
     id: '2', label: '应用部署', value: 'deploy' },
    {
     id: '3', label: '应用验证', value: 'validate' },
    {
     id: '4', label: '镜像同步', value: 'sync' }
  ]
  private stepForm: any = {
    
    new_or_edit: 'new',
    step_name: '',
    step_type: '',
    step_func: '',
    step_url: '',
    step_msg: ''
  }
  private templateForm: any = {
    
    name: '',
    msg: ''
  }
  private templateRules: any = {
    
    name: [{
     required: true, message: '模板名称不能为空', trigger: 'blur' }],
    msg: [{
     required: true, message: '模板说明不能为空', trigger: 'blur' }]
  }
  private stepRules: any = {
    
    step_name: [{
     required: true, message: '步骤名不能为空', trigger: 'blur' }],
    step_type: [{
     required: true, message: '类型不能为空', trigger: 'blur' }],
    step_func: [{
     required: true, message: '功能不能为空', trigger: 'blur' }]
  }
  private index: any = '';
  private selectValue: any = '';

  private addBefore(i: any): void{
    
    this.templateAddDisable = false;
    this.stepForm.step_name = '';
    this.stepForm.step_type = '';
    this.stepForm.step_func = '';
    this.stepForm.step_url = '';
    this.stepForm.step_msg = '';
    this.list.splice(i, 0, {
    
      id: this.id++,
      new_or_edit: 'new',
      step_name: '',
      step_type: '',
      step_func: '',
      step_url: '',
      step_msg: ''
    });
    if (this.list.length !== 0) {
    
      this.showEndSteps = false;
    };
    this.selectValue = '';
    let stepsArrey = document.getElementsByTagName('textarea');
    if(i) {
     window.setTimeout(() => {
     stepsArrey[i+1].focus()}, 0)}
    else {
     window.setTimeout(() => {
     stepsArrey[1].focus()}, 0)};
  }
  private addAfter(i: any): void{
    
    this.stepForm.step_name = '';
    this.stepForm.step_type = '';
    this.stepForm.step_func = '';
    this.stepForm.step_url = '';
    this.stepForm.step_msg = '';
    let stepsArrey = document.getElementsByTagName('textarea');
    if(i == 0) {
    
      window.setTimeout(() => {
     stepsArrey[2].focus(); }, 0);
    } else if(i > 0) {
    
      i = i + 1;
      window.setTimeout(() => {
     stepsArrey[i+1].focus(); }, 0);
    };
    this.list.splice(i, 0, {
    
      id: this.id++,
      new_or_edit: 'new',
      step_name: '',
      step_type: '',
      step_func: '',
      step_url: '',
      step_msg: ''
    });
  }
  private deleteStep(i: any): void {
    
    this.list.splice(i, 1);
    if (this.list.length === 0) {
    
      this.showEndSteps = true;
      this.templateAddDisable = true;
      this.stepForm = {
     new_or_edit: 'new', step_name: '', step_type: '', step_func: '', step_url: '', step_msg: '' };
    };
    let stepsArrey = document.querySelectorAll('textarea');
    for(let i = 1; i < stepsArrey.length-1; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
  }
  private iptFocus(v: any, i: any): void {
    
    this.stepForm.step_name = v.step_name;
    this.stepForm.step_type = v.step_type;
    this.stepForm.step_func = v.step_func;
    this.stepForm.step_url = v.step_url;
    this.stepForm.step_msg = v.step_msg;
    let stepsArrey = document.querySelectorAll('textarea');
    this.index = i + 1;
    for(let i=1; i<stepsArrey.length-1; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
    stepsArrey[this.index].style.backgroundColor = '#409eff';
    stepsArrey[this.index].style.color = '#fff';
  }
  private iptBlur(v: any, i: any): void {
    
    this.index = i;
  }

  private stepnameChange(selVal: any): void {
    
    this.list[this.index].step_name = selVal;
    this.stepForm.step_name = selVal;
  }
  private steptypeChange(selVal: any): void {
    
    this.list[this.index].step_type = selVal;
  }
  private featureChange(selVal: any): void {
    
    this.list[this.index].step_func = selVal;
  }
  private urlChange(selVal: any): void {
    
    this.list[this.index].step_url = selVal;
  }
  private remarksChange(selVal: any): void {
    
    this.list[this.index].step_msg = selVal;
  }
  private closeDialog(): void {
    
    this.$router.push('/conf/template')
  }

  private confirm() {
    
    if(this.templateForm.name == '') return this.$message.error('模板名称不能为空');
    if(this.templateForm.msg == '') return this.$message.error('模板说明不能为空');
    if(this.stepForm.step_name == '') return this.$message.error('步骤名不能为空');
    if(this.stepForm.step_type == '') return this.$message.error('步骤类型不能为空');
    if(this.stepForm.step_func == '') return this.$message.error('步骤功能不能为空');
    let stepsMessage = [];
    let stepsArrey = document.querySelectorAll('textarea');
    for(let i = 1; i < stepsArrey.length-1; i++) {
    
      stepsArrey[i].style.backgroundColor = '#ecf5ff';
      stepsArrey[i].style.color = '#409eff';
    };
    for (let i = 1; i < stepsArrey.length-1; i++) {
    
      if(stepsArrey[i].value != '') {
    
        stepsMessage.push(stepsArrey[i].value);
      } else {
    
        for (let i = 1; i < stepsArrey.length-1; i++) {
    
          if(stepsArrey[i].value === '') {
    
            stepsArrey[i].style.backgroundColor = '#EE1111';
            stepsArrey[i].style.color = '#fff';
          };
        }
        return this.$message({
    type: 'error', message: '请填写完整的流程'});
      }
    };
    let params = {
    
      id: 0,
      name: this.templateForm.name,
      msg: this.templateForm.msg,
      steps: this.list
    };
    console.log(params)
  }
  private replace(): void{
    
    this.list = [];
    this.templateForm = {
     name: '', msg: '' };
    this.stepForm = {
     new_or_edit: 'new', step_name: '', step_type: '', step_func: '', step_url: '', step_msg: '' };
    this.templateAddDisable = true;
    this.showEndSteps = true;
  }
}
</script>
<style lang="less" scoped>
.template_box {
    
  margin-top: -8px;
  background-color: #fff;
  min-height: 680px;
  .template_in {
    
    margin: 5px 0 20px 10px;
    padding: 15px 0;
    width: 720px;
    letter-spacing: 1px;
  }
  h1 {
    
    text-align: center;
    margin-bottom: 20px;
    font-size: 20px;
  }
}
/deep/ .el-form-item--small.el-form-item {
    
    margin-bottom: 12px;
}
/deep/ .el-input--small .el-input__inner, .el-input--small .el-textarea__inner {
    
    font-size: 12px;
}
/deep/ .el-input--small .el-textarea__inner {
    
    font-size: 12px;
}
/deep/ .el-input--small .el-input__inner {
    
    height: 28px;
    line-height: 28px;
}
/deep/ textarea {
    
  font: 400 13.3333px Arial;
  resize: none;
}
/deep/ .step_box textarea {
    
  outline: 0;
  caret-color: transparent;
}
 .step_box textarea::-webkit-input-placeholder {
    
  color: #ccc;
}
.templateInfo {
    
  padding: 0 30px 2px 50px;
  margin: 0 auto;
  margin-top: 10px;
  width: 600px;
}
.stepInfo {
    
  background-image: linear-gradient(to right, #ccc 0%, #ccc 50%, transparent 50%);
  background-size: 14px 2px;
  background-repeat: repeat-x;
  padding: 15px 10px 0 50px;
  margin: 10px auto 25px;
  width: 600px;
  p {
    
    font-size: 14px;
    color: grey;
    margin: 5px 0 15px -10px;
  }
}
.confirmBox {
    
  text-align: center;
}
button {
    
    outline: 0;
  }
.step_box {
    
  min-height: 72px;
  width: 810px;
  display: flex;

  .start-steps,
  .end-steps {
    
    width: 90px;
    position: relative;
    padding: 15px 30px 15px 0;
  }
  .end-steps {
    
    box-sizing: border-box;
    position: relative;
    padding: 15px 0 15px 15px;
    .stepsAdd {
    
      left: -19px;
    }
  }
  .start-btn,
  .end-btn {
    
    width: 90px;
    height: 40px;
    border: 1px solid #b3d8ff;
    border-radius: 20px;
    text-align: center;
    color: #409eff;
    line-height: 40px;
    font-size: 12px;
    cursor: pointer;
    background: #ecf5ff;
  }
}
.end-steps::before {
    
  content: '';
  position: absolute;
  top: 50%;
  left: -30px;
  width: 40px;
  height: 1px;
  background: #c0c4cc;
}
.end-steps::after {
    
  position: absolute;
  content: '';
  width: 0;
  height: 0;
  border-width: 5px;
  border-style: dashed solid;
  top: 50%;
  left: 10px;
  margin-top: -4px;
  border-color: transparent transparent transparent #c0c4cc;
}
.stepsAdd-before {
    
  display: none;
  left: -19px;
  z-index: 2;
}
.stepsAdd {
    
  font-size: 14px;
  text-align: center;
  position: absolute;
  top: 50%;
  border-radius: 100%;
  width: 20px;
  height: 20px;
  line-height: 18px;
  margin-top: -10px;
  background-color: #409eff;
  color: #fff;
  z-index: 1;
  cursor: pointer;
}
.stepsAdd-end {
    
  display: block;
}
.stepsAdd-after {
    
  display: none;
  right: -1px;
  z-index: 2;
}
.end-steps:hover {
    
.stepsAdd-after {
    
  display: block;
  }
}
.step:hover {
    
  .stepsAdd-before {
    
    display: block;
  }
  .stepsAdd-after {
    
    display: block;
  }
  .sb-close {
    
    display: block;
  }
}
.sb-close {
    
  cursor: default;
  display: none;
  width: 16px;
  height: 16px;
  border-radius: 16px;
  color: #fff;
  text-align: center;
  position: absolute;
  color: #fff;
  background: #f56c6c;
  font-size: 16px;
  border-radius: 50%;
  top: 3px;
  right: 23px;
  line-height: 12px;
}
.buttons {
    
  margin-top: 35px;
}
.ghost {
    
  opacity: 0.5;
  background: #c8ebfb;
}
.list-group {
    
  display: flex;
  flex-wrap: wrap;
}
.step::before {
    
  content: '';
  position: absolute;
  top: 50%;
  left: -30px;
  width: 40px;
  height: 1px;
  background: #c0c4cc;
}
.step {
    
  position: relative;
  padding: 10px 30px 10px 15px;
}
.step::after {
    
  position: absolute;
  content: '';
  width: 0;
  height: 0;
  border-width: 5px;
  border-style: dashed solid;
  top: 50%;
  left: 10px;
  margin-top: -4px;
  border-color: transparent transparent transparent #c0c4cc;
}
.list-group-item {
    
  position: relative;
  width: 90px;
  box-sizing: border-box;
  border-radius: 4px;
  border: 1px solid #409eff;
  height: 48px;
  overflow: hidden;
  cursor: pointer;
  text-align: center;
  padding: 0 5px;
  font-size: 12px;
  line-height: 48px;
  background: #ecf5ff;
  color: #409eff;
}
</style>

3、效果演示

在这里插入图片描述

This project demo is that’s all, thanks for your reading!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/SmallTeddy/article/details/106901968

智能推荐

数据指标体系命名规范-程序员宅基地

文章浏览阅读3.8k次,点赞2次,收藏10次。原子指标定义原子指标 = 单一业务修饰词+基础指标词根,例如:支付金额-payment_amt命名规范派生指标定义派生指标 = 多业务修饰词+基础指标词根,派生指标继承原子指标的特性,例如:T+180体系课商品复购率,其中T+180是时间修饰词、体系课复购是业务修饰词、比率是基础指标词根命名规范日期类指标命名规范命名时要遵循:业务修饰词+基础指标词根+聚合修饰词(日期修饰词)。将日期后缀加到名称后面,如下图所示:聚合类型指标命名规范命名时要遵循:业务修饰词+基础指标词根+聚

怎样让一个div高度和浏览器高度一样_如何让div的高度等于浏览器可见区域的高度浏览器滚动div始终覆盖浏览器的整个-程序员宅基地

文章浏览阅读6.7k次,点赞2次,收藏2次。这个老生长谈的问题,不知困扰了多少前端开发人员,和后端程序员,其实很简单,这里写出来,让大家分享下,有很多人说,我已经设置div 100%了,怎么还没效果,我想说的是,有一个关键的东东,你没设置,html,body{height:100%;overflow:hidden;}哈哈,这回你会了吧,要同时设置。_如何让div的高度等于浏览器可见区域的高度浏览器滚动div始终覆盖浏览器的整个

cisco 2960 VLAN MAC_盘点Mac上的触控板(鼠标)增强工具-程序员宅基地

文章浏览阅读147次。今天小编给大家推荐几款Mac上好用的触控板/鼠标增强工具,拥有这些软件可以为触控板添加各种自定义的快捷键和手势动作,为鼠标的右键菜单添加功能,提高工作效率。一、BetterTouchTool触控板功能增强软件,一款专为Mac用户开发的Magic Mouse鼠标功能增强制作的软件。可以触发任意键盘快捷键和100多个预定义操作的组合,您几乎可以控制Mac的每个方面。BetterTouchTool fo...

cas 单点登录服务端客户端配置-程序员宅基地

文章浏览阅读124次。首先,下载cas-server-3.5.2-releasehttp://pan.baidu.com/s/1GJ8Gscas-client-3.2.1-releasehttp://pan.baidu.com/s/1glKFB提供俩个下载地址:先从服务端配置:我是新建一个web工程cas-server将 建几个文件夹src/libssrc/loc...

CSS 设置文字间距_css字间距-程序员宅基地

文章浏览阅读4.7w次,点赞17次,收藏53次。一、css word-spacing属性设置字间距(单词的间距)word-spacing 属性增加或减少单词间的空白(即字间隔);在这个属性中,“字” 定义为由空白符包围的一个字符串。也就是说该属性是以空格为基准进行调节间距的,如果多个字母被连在一起,则会被word-spacing视为一个单词;如果汉字被空格分隔,则分隔的多个汉字就被视为不同的单词,word-spacing属性此时有效。语法:word-spacing:值;normal:定义单词间的标准空间,默认值。 length:定义单词间的固定空_css字间距

关于安卓蓝牙2.0的app开发原理-程序员宅基地

文章浏览阅读805次。最近时间比较宽裕,觉得自己可以写一些东西来总结一下工作,索性就写一篇关于安卓蓝牙的开发总结吧安卓蓝牙开发其实也就是socket的开发,同时分为服务端和客户端,下面我就按照我的开发流程来降整个的安卓蓝牙2.0开发叙述一下,蓝牙4.0BLE我也会在之后给大家更新首先,我们要注册蓝牙相关的广播并在manifest中给出相应的权限(安卓6.0之后由于相应的底层改变,注册权限的时候不仅要给蓝牙的权限

随便推点

matplotlib绘制多张图、多子图、多例图_matplotlib同时绘制8个图-程序员宅基地

文章浏览阅读1.7k次。绘制多图关键:fig = plt.figure(1) 表示新建第几个图import matplotlib.pyplot as pltfig = plt.figure(1)plt_rec_loss = [1,2,3,4,5,6]plt_rec_recall = [4,3,6,5,8,9]plt.xlabel("epoch")plt.ylabel("loss")plt.plot(r..._matplotlib同时绘制8个图

RHCSA第五天作业-程序员宅基地

文章浏览阅读208次。1、新建几个普通用户wukong,wuneng,wujing,他们都属于xiyouji组的成员,其中wujing没有和系统交互的shell。[root@localhost ~]# groupadd xiyouji[root@localhost ~]# useradd -g xiyouji wukong[root@localhost ~]# useradd -g xiyouji wuneng[root@localhost ~]# useradd -g xiyouji wujing[root@loc

一个好用的数据分析工具:Cftool-程序员宅基地

文章浏览阅读4.8k次。同事最近在做数据分析,计算完全依赖于计算器,然后一个小规模的矩阵,就是用计算器一个个算出来;程序员看不下去,给他写了个exe,cmd下输入要求的数据,就直接给输出了。今天他在做数据分析,给了x-y数据,让我找拟合关系。先前接触过cftool,于是直接拿来用了:将x\y按照同样维度格式输入;命令行输入cftool,会出现一个窗口;将x\y数据加载;选择权重关系(同样权重就忽略此项);...

OpenCL错误码转字符串_cl_exec_status_error_for_events_in_wait_list-程序员宅基地

文章浏览阅读638次。OpenCL错误码转字符串(以中文表示)错误代码位:0 ~ -19、-30 ~ -68const char* errorCodeToString(cl_int errCode) { const char* err = NULL; switch (errCode) { case CL_SUCCESS: err = "CL_SUCCESS:命令成功执行,没有出现错误!"; break..._cl_exec_status_error_for_events_in_wait_list

获取本年、本月、本周时间范围_js获取时间(本周、本季度、本月..)-程序员宅基地

文章浏览阅读1k次。Js代码/*** 获取本周、本季度、本月、上月的开端日期、停止日期*/var now = new Date(); //当前日期var nowDayOfWeek = now.getDay(); //今天本周的第几天var nowDay = now.getDate(); //当前日var nowMonth = now.getMonth(); //当前月var nowYear = now.getYear..._js 本周 本月 时间段

GD32三种低功耗例程-程序员宅基地

文章浏览阅读1.1w次,点赞5次,收藏25次。GD32F303ZET6低功耗例程,睡眠模式、深度睡眠模式、待机模式

推荐文章

热门文章

相关标签