Vue蛇形流程图组件(根据父容器宽度自适应自身宽度)

 组件代码

<template>
  <!-- 蛇形流程图-->
  <div class="snakeFlowchart ">
    <div style="width: 100%; display: flex; position: relative; margin-top: 20px">
      <!--左侧曲线-->
      <div :style="`width:${sideWidth}vw ; margin-left: 30px`">
        <div>
          <span  :style="`margin-top:${ItemHeight/2}px ; opacity: 0`" class="headerRadio"></span>
          <div v-if="experienceData.length > Index">
						<span
              v-for="(num, index) in leftRows"
              :key="index"
              class="hingelisHeard"
              :style="`height:${ItemHeight}px ; margin-top:${ItemHeight}px; ;border: ${LineWidth}px ${LineType} ${LineColor};`"
            ></span>
          </div>
        </div>
      </div>
      <!--中间流程项-->
      <div style="width: 96%">
        <div
          style="display: flex"
          v-for="(item, index) in experienceData"
          :key="index"
        >
          <div style="display: flex ;justify-content: flex-start;" v-if="(index + 1) % 2 !== 0">
            <div
              class="timeline"
              v-for="(v, i) in DisplayProcessing(experienceData, index + 1)"
              :key="i"
              :style="(i + 1) % Index !== 0 ? `width:${ItemWidth}vw ; height:${ItemHeight}px` : `width: ${IconWidth}vw;height:${ItemHeight}px`"
            >
             <div class="NodesItem">
               <div class="timeNodes">
                 <div class="timeContent">
                   {{v.content }}
                 </div>
                 <div class="nodeTimes">
                   {{v.createTime }}
                 </div>
               </div>
             </div>
              <div class="Nodes " :style="{width:`${IconWidth}vw`,height:`${IconWidth}vw`, backgroundColor:(v.last ?CurrentItemColor:DoneItemColor)}">
              </div>
              <div
                class="border"
                v-if="
									(i + 1) % Index != 0 &&
									i != DisplayProcessing(experienceData, index + 1).length - 1
								"
              >
                <div class="borderTime " :style="`border-bottom:${LineWidth}px ${LineType} ${LineColor}`"></div>
              </div>
            </div>
          </div>
          <div style="display: flex ;justify-content: flex-end;" v-else>
            <div
              class="timeline2"
              v-for="(v, i) in DisplayProcessing(experienceData, index + 1)"
              :key="i"
              :style="
								i + 1 === 1 &&
								DisplayProcessing(experienceData, index + 1).length !== 1
									? `width: ${IconWidth}vw;height:${ItemHeight}px`
									: `width:${ItemWidth}vw;height:${ItemHeight}px`
							"
            >
              <div class="Nodes " :style="{width:`${IconWidth}vw`,height:`${IconWidth}vw`, backgroundColor:(v.last ?CurrentItemColor:DoneItemColor)}">
              </div>
              <div class="border" v-if="i !== 0">
                <div class="borderTime" :style="`border-bottom:${LineWidth}px ${LineType} ${LineColor}`"></div>
              </div>

              <div class="NodesItem">
                <div class="timeNodes">
                  <div class="timeContent">
                    {{v.content }}
                  </div>
                  <div class="nodeTimes">
                    {{v.createTime }}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <!--右侧曲线-->
      <div :style="`width:${sideWidth}vw ; margin-right: 30px`">
        <div>
          <span class="hingelis" :style="`margin-top: ${ItemHeight/2}px;height:${ItemHeight}px; border: ${LineWidth}px ${LineType} ${LineColor};`" v-if="experienceData.length > Index"></span>
          <div v-if="experienceData.length > Index * 2">
						<span
              class="hingelis"
              v-for="(num, index) in rightRows"
              :key="index"
            ></span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    // 流程数据
    chartData: {
      type: Array,
      default: () => {
        return [];
      },
    },
    //每行几条数据
    Index: {
      type: Number,
      default: 5,
    },
    // 行高
    ItemHeight: {
      type: String,
      default: '80',
    },
    // 线宽度
    LineWidth:{
      type: Number,
      default: 1
    },
    // 线样式(实线/虚线)
    LineType:{
      type: String,
      default: 'dashed',
    },
    // 线颜色
    LineColor:{
      type: String,
      default: '#a0a0a5',
    },
    //已完成流程颜色
    DoneItemColor: {
      type: String,
      default: '#a0a0a5',
    },
    // 当前流程颜色
    CurrentItemColor:{
      type: String,
      default: '#10bc28',
    },
    //小球大小
    IconWidth:{
      type: String,
      default: '0.85',
    }
  },
  data() {
    return {
      // 流程数据
      experienceData: this.chartData,
      leftRows: 0,
      rightRows: 0,
      leftShow: false,
      rightShow: false,
      // 宽度
      ItemWidth:"19.4",
      // 拐弯位置宽度
      sideWidth:'',
    };
  },
  watch: {
    chartData: {
      handler(newVal) {
        //时间线数据
        this.experienceData = newVal;
        let rows = Math.ceil(newVal.length / this.Index);
        this.leftRows = rows === 2 ? 0 : rows % 2 === 0 ? parseInt(rows / 2) - 1 : parseInt(rows / 2);
        this.rightRows = rows === 4 ? 1 : rows % 2 === 0 ? parseInt(rows / 2) % 2 === 0 ? parseInt(rows / 2) >= 4
                  ? parseInt(rows / 2) - 1
                  : parseInt(rows / 2)
                : parseInt(rows / 2) - 1
              : parseInt(rows / 2) - 1;
        this.leftShow = rows % 2 === 0;
        this.rightShow = rows === 1 ? false : rows % 2 === 1;
      },
      immediate: true,
    },
  },
  mounted() {
    this.initWidth()
  },
  methods: {
    // 初始化宽度
    initWidth(){
      let p  = document.querySelector(".snakeFlowchart").parentNode;
      // 1VW宽度
      let VW = window.innerWidth/100
      // 中间流程部分占8成,算出每一段长度
      this.ItemWidth= ((Number(p.clientWidth))*0.70/VW)/(this.Index-1)
      console.log(this.ItemWidth)
      // 两边拐弯部分共占2成
      this.sideWidth = ((Number(p.clientWidth))*0.30/VW)/2
    },
    // 计算数据排列
    DisplayProcessing(Arg, Num) {
      //数据循环处理
      let arr = Arg.slice(this.Index * (Num - 1), this.Index * Num);
      arr = Num % 2 === 0 ? arr.reverse() : arr;
      return arr;
    },
  },
};
</script>
<style scoped lang="scss">
.timeline {
  width: 21.4vw;
  display: flex;
  align-items: center;
}
.timeline2 {
  width: 21.4vw;;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
.border {
  width: 100%;
  justify-content: center;
  align-items: center;
  display: flex;
  .borderTime {
    width: 100%;
  }
}

.NodesItem{
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 0.85vw;
  margin-top: 1.85vw;
}
.Nodes {
  position: absolute;
  justify-content: center;
  align-items: center;
  display: flex;
  border-radius: 50%;
  background-color:  #a0a0a5;
}

.timeNodes {
  position: relative;
  top: 5px;
  .timeContent{
    position: relative;
    text-align: center;
    width: 8vw;
    font-size: 12px;
  }
  .nodeTimes{
    position: absolute;
    text-align: center;
    width: 8vw;
    font-size: 12px;
  }
}
.hingelis {
  content: "";
  display: block;
  width: 100%;
  border-radius: 0 35px 35px 0px;
  border-left: 0px !important;
}
.hingelisHeard {
  content: "";
  display: block;
  width: 100%;
  border-radius: 35px 0px 0px 35px;
  border-right: 0px !important;
}

.headerRadio {
  display: block;
  width: 100%;
  border-bottom: 1px solid #cccccc;
  position: relative;
}


</style>

父组件引用

<template>
  <div class="app-container">
    <el-card class="box-card">
      <SnakeFlowchart v-if="FlowData.length > 0" :chartData="FlowData" :Index="5"/>
    </el-card>
  </div>
</template>

<script>
import SnakeFlowchart from "@/components/SnakeFlowchart/index.vue";

export default {
  components: { SnakeFlowchart },
  name: 'process-track',
  props: {

  },
  data() {
    return {
      FlowData: [
        {

          id: 7204928,
          content: "步骤1",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: null,
          createTime: "2024-01-03",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤2",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-01-04",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤3",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-01-05",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤4",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤5",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤6",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤7",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤8",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤9",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 0
        },
        {

          id: 7204929,
          content: "步骤10",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 1
        },


        {

          id: 7204929,
          content: "步骤15",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 2
        },
        {

          id: 7204929,
          content: "步骤16",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 2
        },
        {

          id: 7204929,
          content: "步骤17",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 2
        },

        {

          id: 7204929,
          content: "步骤20",
          smallClass: "UpdateOutBoundAgingPlanning",
          bigClass: "SCFXD",
          createTime: "2024-03-01",
          createUser: "Mia",
          outBoundAgingPlanningId: 1342,
          status: 2,
          last:true
        }
      ]
    }
  },

}
</script>
<style scoped>

</style>

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值