1.效果展示

在这里插入图片描述

2.代码

实现

  • 父页面
  • 子页面timeline.vue
  • 子页面card.vue

父页面

 <div v-for="(v, i) in uni_data" :key="'id' + i" class="year-item">
        <timeline :time-data="v">
          <template slot="cardSlot" slot-scope="scope">
            <!--这里采用作用域插槽-可以自己自定义卡片样式-->
            <card :card-data="scope.card"></card>
          </template>
        </timeline>
      </div>

在这里插入图片描述

子页面timeline.vue

<template>
  <div class="timeline-main">
    <!--年月标题-->
    <div class="timeline-title">
      {{ timeData.yearData }}
      <i
        :class="showCards ? 'el-icon-arrow-down' : 'el-icon-arrow-right'"
        @click="showCards = !showCards"
      ></i>
    </div>
    <ul class="timeline-body">
      <!--时间线顶部圆点-->
      <li class="timeline-item-head">
        <div class="item-node"></div>
        <div class="item-tail"></div>
      </li>
      <!--时间线内容-->
      <template v-if="showCards">
        <li
          v-for="(mouthItem, i) in timeData.mouthData"
          :key="'mm' + i"
          class="timeline-item"
        >
          <div class="item-left">
            <div class="item-left-data">{{ mouthItem.dateData }}</div>
            <div class="item-left-total">
              <div class="item-left-total-text">{{ mouthItem.dateArr.length }}</div>
              <div class="item-left-total-end"></div>
            </div>
          </div>
          <div class="item-tail"></div>
          <div class="item-node"></div>
          <div class="item-content">
            <slot name="cardSlot" v-for="v in mouthItem.dateArr" :card="v"></slot>
          </div>
        </li>
      </template>
      <!--时间线尾部圆点-->
      <li class="timeline-item-foot">
        <div class="item-node"></div>
        <div class="item-tail"></div>
      </li>
    </ul>
  </div>
</template>
 
<script>
export default {
  name: "Timeline",
  props: {
    timeData: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      showCards: true,
    };
  },
};
</script>
 
<style scoped lang="less">
.timeline-main {
  padding: 0 0 0 20px;

  .timeline-title {
    margin-bottom: 10px;
    font-weight: bold;

    i {
      cursor: pointer;
    }
  }

  .timeline-body {
    margin: 0;
    font-size: 14px;
    list-style: none;
    // 顶尾圆圈
    .timeline-item-head,
    .timeline-item-foot {
      position: relative;
      height: 15px;

      .item-tail {
        position: absolute;
        left: 45px;
        height: 100%;
        border-left: 2px solid #e4e7ed;
      }

      .item-node {
        position: absolute;
        left: 42px;
        width: 8px;
        height: 8px;
        background-color: #e4e7ed;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    }

    .timeline-item-foot {
      .item-node {
        top: 14px;
      }
    }

    // 时间线主体内容
    .timeline-item {
      position: relative;
      padding-bottom: 10px;

      .item-left {
        position: absolute;
        top: 13px;
        left: -9px;

        .item-left-data {
          font-weight: bold;
          line-height: 20px;
        }

        .item-left-total {
          display: flex;
          font-size: 12px;

          .item-left-total-text {
            padding: 0 3px;
            line-height: 20px;
            color: #ffffff;
            background: #409eff;
          }

          .item-left-total-end {
            width: 0;
            height: 0;
            border-top: 10px solid transparent;
            border-left: 6px solid #409eff;
            border-bottom: 10px solid transparent;
          }
        }
      }

      .item-tail {
        position: absolute;
        left: 45px;
        height: 100%;
        border-left: 2px solid #e4e7ed;
      }

      .item-node {
        position: absolute;
        top: 38px;
        left: 41px;
        width: 6px;
        height: 6px;
        background-color: #ffffff;
        border: 2px solid #409eff;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
      }

      .item-content {
        position: relative;
        padding-top: 15px;
        padding-left: 60px;
        // top: -3px;
      }
    }
  }
}
</style>

子页面card.vue

<template>
  <div class="item-content-card" @click="goDetail()">
    <div class="time-title" :class="statusStyle(cardData.status)">
      <i class="el-icon-time"></i>
      <!-- {{ cardData.createTime.slice(-8) }} -->
      <div class="item-status"><b>{{ formatStatus(cardData.status) }}</b></div>
    </div>
    <div class="time-content">
      <div class="time-content-no">
        <div class="time-content-no-circle" :class="{'time-content-delete' : cardData.type!=1}"></div>
        {{ cardData.workNo }}
      </div>
      <div class="time-content-name">
        <span>{{ cardData.name }}</span>
        新增/导入/删除
        <div v-if="showRevoke()" class="opera-icon-back" title="撤销" @click.stop="revokeWorkFlow"></div>
        <div v-if="showRevoke() && cardData.status == 4" class="opera-icon-edit" title="编辑" @click.stop="editWorkFlow"></div>
      </div>
    </div>
  </div>
</template>
 
<script>
 
export default {
  name: 'TheWorkNoteCard',
  props: {
    cardData: {
      type: Object,
      default: () => ({})
    }
  },
  methods: {
    // 跳转详情页面
    goDetail() {
      this.$router.push({});
    },
    // 显示撤销
    showRevoke() {
      // 判断符合条件的逻辑
    },
    // 撤销
    revokeWorkFlow() {
    },
    // 编辑被驳回
    editWorkFlow() {
    },
    statusStyle(v) {
      if (String(v) === '2') {
        return 'time-status-unreview';
      } else if (String(v) === '3') {
        return 'time-status-success';
      } else if (String(v) === '4' || String(v) === '5') {
        return 'time-status-back';
      } else {
        return 'time-status-unreview';
      }
    },
    formatStatus(v) {
      if (String(v) === '2') { // 待审核
        return '待审核';
      } else if (String(v) === '3') { // 通过
        return '通过';
      } else if (String(v) === '4') { // 驳回
        return '驳回';
      } else if (String(v) === '5') { // 撤销
        return '撤销';
      } else {
        return '--';
      }
    },
  }
};
</script>
 
<style scoped lang="less">
.item-content-card {
  cursor: pointer;
  border-radius: 4px;
  background-color: #f7f9fa;
  margin-bottom: 10px;
 
  .time-title {
    position: relative;
    box-sizing: border-box;
    height: 50px;
    padding: 15px;
    border-bottom: 1px solid #e4e4e4;
 
    i {
      font-size: 16px;
    }
 
    .item-status {
      position: absolute;
      font-size: 12px;
      top: 13px;
      right: 0;
      width: 40px;
      text-align: center;
      z-index: 1;
      transform: rotate(45deg)
    }
 
    &:after {
      content: "";
      position: absolute;
      top: 0;
      right: 0;
      border-style: solid;
      border-width: 25px 25px 25px 25px;
      width: 0px;
      height: 0px;
    }
  }
 
  .time-status-unreview {
    .item-status {
      color: #409EFF;
    }
 
    &:after {
      border-color: #d3e7fb #d3e7fb transparent transparent;
    }
  }
 
  .time-status-success {
    .item-status {
      color: #67C23A;
    }
 
    &:after {
      border-color: #dbeed4 #dbeed4 transparent transparent;
    }
  }
 
  .time-status-back {
    .item-status {
      color: #E6A23C;
    }
 
    &:after {
      border-color: #f4e7d4 #f4e7d4 transparent transparent;
    }
  }
 
  .time-content {
    padding: 15px;
 
    .time-content-no {
      margin-bottom: 10px;
 
      .time-content-no-circle {
        width: 10px;
        height: 10px;
        display: inline-block;
        background-color: #8ec850;
        border-radius: 50%;
        margin-right: 6px;
      }
 
      .time-content-delete {
        background-color: #666666;
      }
    }
 
    .time-content-name {
      line-height: 20px;
      padding-left: 20px;
 
      span {
        margin-right: 20px;
      }
 
      .opera-icon-back {
        margin-left: 30px;
        display: inline-block;
        width: 18px;
        height: 18px;
        cursor: pointer;
        //background: url('../images/rollback.png') no-repeat;
        background-size: 18px;
 
        &:hover {
         // background: url('../images/rollback_h.png') no-repeat;
          background-size: 18px;
        }
      }
 
      .opera-icon-edit {
        margin-left: 5px;
        display: inline-block;
        width: 18px;
        height: 18px;
        cursor: pointer;
        //background: url('../images/edit.png') no-repeat;
        background-size: 18px;
 
        &:hover {
          //background: url('../images/edit_h.png') no-repeat;
          background-size: 18px;
        }
      }
    }
  }
 
  &:hover {
    box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.176470588235294)
  }
}
</style>
Logo

前往低代码交流专区

更多推荐