首页 > 技术文章 > vue timeLine 时间轴

lpp-11-15 2020-09-17 16:17 原文

需求:

纵坐标为日期 横坐标为 时间点 且 横坐标有分支(前提事件)

纵坐标是用elementUi里的事件轴实现。

 

 实现:

<template>
  <div class="processInfo" v-loading="openAccountProcessLoading">
    <common-title title=”时间轴"></common-title>
    <!-- <div style="display:flex; width:900px;margin:100px auto;"> -->
    <div class="timeLineTitle" >
      <div class="timeLineItem">
        <div class="finish timeLineStatus"></div>
        <div>已完成</div>
      </div>
      <div class="timeLineItem">
        <div class="being timeLineStatus"></div>
        <div>进行中</div>
      </div>
      <div class="timeLineItem">
        <div class="wating timeLineStatus"></div>
        <div>待开始</div>
      </div>
      <div class="timeLineItem">
        <div class="timeOut timeLineStatus"></div>
        <div>超时警告</div>
      </div>
    </div>
    <el-timeline style="margin-left: 100px; margin-top: 10px;" id="timeLineDate">
      <el-timeline-item
        v-for="(activity, index) in activities"
        :key="index"
        icon="el-icon-timer"
        type="primary"
        size="large"
        :timestamp="activity.timestamp"
        placement="top"
      >
        <!-- <div>1111</div> -->
        <div style="display:flex;">
          <timeLine :timeLineList="activity.timeLineList"></timeLine>
        </div>
      </el-timeline-item>
    </el-timeline>
  </div>
</template>

<script>
import { businessProcess } from '@/api/dataGovern'
import CommonTitle from '@/components/dataGovern/common/commonTitle'
import timeLine from './timeLine'
export default {
  components: { CommonTitle, timeLine },
  data() {
    return {
      openAccountProcessLoading:true,
      activities: [
        {
          timestamp: '4月1日',
          timeLineList: [
            {
              status: '',
              timestamp: '10:00',
              info: 'BOSS账单',
              timeLineBranch: [
                { timestamp: '10:00', status: 'being', info: 'BOSS账单' },
                { timestamp: '12:00', status: 'wating', info: 'CB用户资料下载' },
                { timestamp: '4月30日 12:00', status: 'wating', info: 'CB用户资料下载' },
              ],
            },
            {
              status: 'wating',
              timestamp: '12:00',
              info: '入会',
            },
            {
              status: 'finish',
              timestamp: '13:00',
              info: 'BOSS收入划拨',
            },
            {
              status: 'wating',
              timestamp: '12:00',
              info: '入会',
            },
            {
              status: 'finish',
              timestamp: '13:00',
              info: 'BOSS收入划拨',
            },
          ],
        },
        {
          timestamp: '4月3日',
          timeLineList: [
            {
              status: 'finish',
              timestamp: '13:00',
              info: '工作室更名为:西安拓美网络科技有限公司3',
            },
            {
              status: 'finish',
              timestamp: '14:00',
              info: '工作室更名为:西安拓美网络科技有限公司4',
              timeLineBranch: [
                { timestamp: '4月1日', status: 'timeOut', info: '佣金结算' },
                { timestamp: '4月1日', status: 'timeOut', info: 'z端用户结算' },
                { timestamp: '10:00', status: 'being', info: 'BOSS账单' },
                { timestamp: '12:00', status: 'wating', info: 'CB用户资料下载' },
                { timestamp: '4月30日 12:00', status: 'wating', info: 'CB用户资料下载' },
              ],
            },
            {
              status: 'finish',
              timestamp: '16:00',
              info: '工作室更名为:西安拓美网络科技有限公司5',
            },
            {
              status: 'finish',
              timestamp: '18:00',
              info: '工作室更名为:西安拓美网络科技有限公司6',
            },
            {
              status: 'finish',
              timestamp: '16:00',
              info: '工作室更名为:西安拓美网络科技有限公司5',
            },
            {
              status: 'finish',
              timestamp: '18:00',
              info: '工作室更名为:西安拓美网络科技有限公司6',
            },
          ],
        },
        {
          timestamp: '4月5日',
          timeLineList: [
            {
              status: 'finish',
              timestamp: '16:00',
              info: '工作室更名为:西安拓美网络科技有限公司5',
            },
            {
              status: 'finish',
              timestamp: '18:00',
              info: '工作室更名为:西安拓美网络科技有限公司6',
            },
          ],
        },
        {
          timestamp: '4月6日',
          timeLineList: [
            {
              status: 'finish',
              timestamp: '20:00',
              info: '工作室更名为:西安拓美网络科技有限公司03',
            },
            {
              status: 'finish',
              timestamp: '22:00',
              info: '工作室更名为:西安拓美网络科技有限公司02',
            },
            {
              status: 'finish',
              timestamp: '2016-10-6',
              info: '工作室更名为:西安拓美网络科技有限公司01',
              timeLineBranch: [
                { timestamp: '4月1日', status: 'timeOut', info: 'z端用户结算' },
                { timestamp: '10:00', status: 'being', info: 'BOSS账单' },
                { timestamp: '12:00', status: 'wating', info: 'CB用户资料下载' },
                { timestamp: '4月30日 12:00', status: 'wating', info: 'CB用户资料下载' },
              ],
            },
            {
              status: 'being',
              timestamp: '20:00',
              info: '工作室更名为:西安拓美网络科技有限公司03',
            },
            {
              status: 'finish',
              timestamp: '22:00',
              info: '工作室更名为:西安拓美网络科技有限公司02',
            },
            {
              status: 'finish',
              timestamp: '2016-10-6',
              info: '工作室更名为:西安拓美网络科技有限公司01',
            },
            {
              status: 'finish',
              timestamp: '20:00',
              info: '工作室更名为:西安拓美网络科技有限公司03',
            },
            {
              status: 'finish',
              timestamp: '20:00',
              info: '工作室更名为:西安拓美网络科技有限公司03',
            },
          ],
        },
      ],
    }
  },
   created() {
    this.getbusinessProcess()
  },
  methods: { 
    
  }
}
</script>
<style scoped lang="scss">
h1,
h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
  width: 100%;
}
a {
  color: #42b983;
}
// .main-wrapper{
//     background-color: #fff;
// }
.processInfo {
  background-color: #fff;
}
.timeLineTitle {
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */

  .timeLineItem {
    display: flex;
    padding: 20px;
    font-size: 12px;
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
  }
  .timeLineStatus {
    width: 12px;
    height: 10px;
    margin: 10px;
    border-radius: 2px;
  }
  .finish {
    background-color: #65bdaf;
  }
  .being {
    background-color: #eabd60;
  }
  .wating {
    background-color: #e2e9f9;
  }
  .timeOut {
    background-color: #ce3820;
  }
}
</style>
<style lang="scss">
.processInfo {
  overflow: auto;
  height: 100%;
  .el-timeline-item {
    padding-bottom: 120px;
  }
  .el-timeline-item__timestamp.is-top {
    position: absolute;
    left: -50px;
    color: #205081;
    /* font-weight: bold; */
    font-family: zcool-gdh;
    font-size: 12px;
  }
  .el-timeline-item__wrapper {
    padding: 0px 15px;
  }
  //   .timeLineDate .el-timeline-item:last-child .el-timeline-item__tail{
  //       display: none;

  //   }
}
</style>

timeLine:

<template>
  <!--时间线-->
  <div style="display:flex; width:95%" class="timeLineClass">
    <!-- 当日志记录不超过9个,全排列 -->
    <div class="container" v-if="timeLineList.length<6">
      <div style="display:flex;">
        <div
          v-for="(item,index) in timeLineList"
          :key="index"
          v-if="index>=0 && index<timeLineList.length-1"
          style="flex:1;display:flex;flex-direction:column;"
        >
          <div style="display:flex">
            <div class="item"></div>
            <div
              class="dot"
              @mouseover="changeActive(index)"
              :class="{active: index === timeIndex}"
            ></div>
            <div class="item"></div>
          </div>
          <div class="item_top">
            <span v-if="timeLineList[index].timestamp">{{timeLineList[index].timestamp}}</span>
          </div>
          <el-tooltip effect="light" placement="top">
            <div slot="content">{{timeLineList[index].info}}</div>
            <div class="item_bottom">
              <div
                class="itemBot_list"
                :style="{backgroundColor:(timeLineList[index].status =='finish' ? '#65bdaf' :(timeLineList[index].status =='being'?'#eabd60':(timeLineList[index].status =='wating'?'#e2e9f9':(timeLineList[index].status =='timeOut'?'#ce3820':''))))}"
              >{{timeLineList[index].info}}</div>
            </div>
          </el-tooltip>
          <!-- 横时间轴分支 -->
          <div
            class="timeLineBranch"
            v-if="timeLineList[index].timeLineBranch && timeLineList[index].timeLineBranch.length>0"
          >
            <el-timeline>
              <el-timeline-item
                v-for="(itemBranch,indexBranch) in timeLineList[index].timeLineBranch"
                :key="indexBranch"
                :timestamp="itemBranch.timestamp"
              >
              <!-- {{itemBranch.info}} -->
              <div :style="{color:(itemBranch.status =='finish' ? '#65bdaf' :(itemBranch.status =='being'?'#eabd60':(itemBranch.status =='wating'?'#e2e9f9':(itemBranch.status =='timeOut'?'#ce3820':''))))}">{{itemBranch.info}}</div>
              </el-timeline-item>
            </el-timeline>
          </div>
        </div>
        <div style="flex:1;display:flex;flex-direction:column;">
          <div style="display:flex">
            <div class="item"></div>
            <div
              class="dot"
              @mouseover="changeActive(timeLineList.length-1)"
              :class="{active: timeLineList.length-1 === timeIndex}"
            ></div>
            <div style="flex:1;"></div>
          </div>
          <div class="item_top">
            <span>{{timeLineList[timeLineList.length-1].timestamp}}</span>
          </div>
          <el-tooltip effect="light" placement="top">
            <div slot="content">{{timeLineList[timeLineList.length-1].info}}</div>
            <div class="item_bottom">
              <div
                class="itemBot_list"
                :style="{backgroundColor:(timeLineList[timeLineList.length-1].status =='finish' ? '#65bdaf' :(timeLineList[timeLineList.length-1].status =='being'?'#eabd60':(timeLineList[timeLineList.length-1].status =='wating'?'#e2e9f9':(timeLineList[timeLineList.length-1].status =='timeOut'?'#ce3820':''))))}"
              >{{timeLineList[timeLineList.length-1].info}}</div>
            </div>
          </el-tooltip>
          <!-- 横时间轴分支 -->
          <div
            class="timeLineBranch"
            v-if="timeLineList[timeLineList.length-1].timeLineBranch && timeLineList[timeLineList.length-1].timeLineBranch.length>0"
          >
            <el-timeline>
              <el-timeline-item
                v-for="(itemBranch,indexBranch) in timeLineList[timeLineList.length-1].timeLineBranch"
                :key="indexBranch"
                :timestamp="itemBranch.timestamp"
              >
              <div :style="{color:(itemBranch.status =='finish' ? '#65bdaf' :(itemBranch.status =='being'?'#eabd60':(itemBranch.status =='wating'?'#e2e9f9':(itemBranch.status =='timeOut'?'#ce3820':''))))}">{{itemBranch.info}}</div>
              </el-timeline-item>
              <!-- <el-timeline-item timestamp="2018/4/12"></el-timeline-item> -->
            </el-timeline>
          </div>
        </div>
      </div>
    </div>
    <!-- 当日志记录超过8个,可以左右滑动 -->
    <div class="container" v-else>
      <div style="display:flex;">
        <div style="flex:1;display:flex;flex-direction:column">
          <!-- <div style="flex:1;display:flex;"> -->
          <div style="display:flex;">
            <!-- <div style="flex:1;"></div> -->
            <div class="item"></div>
            <div
              class="move-button el-icon-arrow-left"
              v-bind:class="{active: left_button_active}"
              :disabled="left_button_disabled"
              @click="moveLeft()"
            ></div>
            <div class="item"></div>
          </div>
          <div class="item_top">
            <span style="color:#000;">左</span>
          </div>
          <!-- <div class="item_bottom">
            <div class="itemBot_end"></div>
          </div>-->
        </div>

        <div
          v-for="(item,index) in timeLineList"
          :key="index"
          v-if="index >= point && index <= point_end"
          style="flex:1;display:flex;flex-direction:column;"
        >
          <div style="display:flex">
            <div class="item"></div>
            <div
              class="dot"
              @mouseover="changeActive(index)"
              :class="{active: index === timeIndex}"
            ></div>
            <div class="item"></div>
          </div>
          <div class="item_top">
            <span>{{timeLineList[index].timestamp}}</span>
          </div>
          <el-tooltip effect="light" placement="top">
            <div slot="content">{{timeLineList[index].info}}</div>
            <div class="item_bottom">
              <div
                class="itemBot_list"
                :style="{backgroundColor:(timeLineList[index].status =='finish' ? '#65bdaf' :(timeLineList[index].status =='being'?'#eabd60':(timeLineList[index].status =='wating'?'#e2e9f9':(timeLineList[index].status =='timeOut'?'#ce3820':''))))}"
              >{{timeLineList[index].info}}</div>
            </div>
          </el-tooltip>
          <!-- 横时间轴分支 -->
          <div
            class="timeLineBranch"
            v-if="timeLineList[index].timeLineBranch && timeLineList[index].timeLineBranch.length>0"
          >
            <el-timeline>
              <el-timeline-item
                v-for="(itemBranch,indexBranch) in timeLineList[index].timeLineBranch"
                :key="indexBranch"
                :timestamp="itemBranch.timestamp"
              >
              <div :style="{color:(itemBranch.status =='finish' ? '#65bdaf' :(itemBranch.status =='being'?'#eabd60':(itemBranch.status =='wating'?'#e2e9f9':(itemBranch.status =='timeOut'?'#ce3820':''))))}">{{itemBranch.info}}</div>
              </el-timeline-item>
            </el-timeline>
          </div>
        </div>
        <div style="flex:1;display:flex;flex-direction:column;">
          <div style="display:flex">
            <div class="item"></div>
            <div
              class="move-button el-icon-arrow-right"
              v-bind:class="{active: right_button_active}"
              :disabled="right_button_disabled"
              @click="moveRight()"
            ></div>
            <div style="flex:1;"></div>
          </div>
          <div class="item_top">
            <span style="color:#000;">右</span>
          </div>
          <!-- <div class="item_bottom">
            <div class="itemBot_end"></div>
          </div>-->
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'timeLine',
  props: ['timeLineList'],
  data() {
    return {
      timeIndex: this.timeLineList.length - 1, //默认当前选择的为最近的时间点
      point: this.timeLineList.length -5, //时间轴只展示5个,初始为最后5个
      point_end: this.timeLineList.length - 1,
      right_button_active: false,
      left_button_active: true,
      left_button_disabled: false,
      right_button_disabled: true,
    }
  },
  methods: {
    changeActive(index) {
      this.timeIndex = index
      console.log('悬浮选择的时间点:', this.timeIndex)
    },
    moveLeft() {
      if (this.point > 0) {
        this.point -= 1
        this.point_end -= 1
        this.timeIndex -= 1
        this.right_button_disabled = false
        this.right_button_active = true
        if (this.point === 0) {
          //如果移到第一个时间点,设置左按钮不可点击
          this.left_button_disabled = true
          this.left_button_active = false
        }
      }
    },
    moveRight() {
      if (this.point_end < this.timeLineList.length - 1) {
        this.point += 1
        this.point_end += 1
        this.timeIndex += 1
        this.left_button_disabled = false
        this.left_button_active = true
        console.log('————————————', this.timeIndex)
        if (this.point_end === this.timeLineList.length - 1) {
          //如果移到最后一个时间点,设置右按钮不可点击
          this.right_button_disabled = true
          this.right_button_active = false
        }
      }
    },
  },
}
</script>

<style scoped lang='scss'>
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
  width: 100%;
}
.container {
  width: 100%;
  height: 30px;
  margin-left: 0px;
  padding-left: 0px;
  margin-bottom: 5px;
}
.dot {
  border: 2px solid #dcdfe6;
  width: 15px;
  height: 15px;
  border-radius: 15px;
  //   background: white;
  background: #499cf0;
  margin: 2px 0px;
  box-sizing: border-box;
}
.item {
  flex: 1;
  border-bottom: 1px solid #dcdfe6;
  margin-bottom: 9px;
  box-sizing: border-box;
  min-width: 100px;
}
.item_top {
  //   flex: 1;
  text-align: center;
  height: 15px;
  margin-top: -40px;
  font-size: 14px;
}
.item_bottom {
  flex: 1;
  text-align: center;
  height: 15px;
  margin-top: 24px;
  font-size: 12px;
  .itemBot_list {
    padding: 4px 8px;
    border-radius: 5px;
    background-color: #6bb9ba;
    height: 26px;
    width: 100px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: inline-block;
    vertical-align: middle;
  }
  .itemBot_end {
    height: 26px;
    visibility: hidden;
  }
}
.move-button {
  border: 2px solid #dcdfe6;
  width: 40px;
  height: 19px;
  border-radius: 19px;
  background: white;
  text-align: center;
  box-sizing: border-box;
}
.active {
  background-color: #fff !important;
  //   border: 3px solid #67c23a;
  border: 3px solid #499cf0;
}
</style>
<style lang="scss">
.timeLineClass {
  .timeLineBranch {
    // display: flex;
    // justify-content: center;
    position: relative;
    // min-height: 45px;
    height: 90px;
    overflow-y: auto;
    overflow-x:hidden;
    .el-timeline {
      //   width: 30px; //和 itemBot_list的width一样宽
      position: absolute;
      left: 50%;
      /* padding-top: 1px; */
      /* height: 100%; */
      margin-left: -12px;
    }
    .el-timeline-item {
      padding-bottom: 10px;
    }
  }
 //横轴时间轴 分支左边时间   
  .el-timeline-item__timestamp.is-bottom {
    font-size: 12px;
    // white-space: nowrap;
    margin-top: 3px;
    position: absolute;
    left: -100px;
    top: 0px;
    text-align: right;
    min-width: 100px;
    padding: 0 5px;
    // margin-left: -60px;
    // float: left;
  }
  //横轴时间轴 分支右边内容   
  .el-timeline-item__content {
    font-size: 12px;
    margin-top: 1px;
    // white-space: nowrap;
    // float: right;
    // margin-right: -40px;
  }
  
  .el-timeline .el-timeline-item .el-timeline-item__tail {
    position: absolute;
    left: 4px;
    height: 100%;
    border-left: 2px solid #e4e7ed;
    display: block;
  }
  .el-timeline .el-timeline-item:last-child .el-timeline-item__tail {
    display: none;
  }
}
</style>

 

横坐标时间轴 借鉴原文git 地址:https://github.com/FareDream/timeLineCase

推荐阅读