index.vue 3.52 KB
<template>
  <view class="timeline">
    <view v-for="(s, i) in renderNodeList" :key="i" class="node">
      <view :class="['dot', s.active ? 'active' : '', !s.isFinish && isEnd && s.nodeName == '结束' ? 'red' : '']" />
      <view class="line" />
      <view class="content">
        <view class="row">
          <text class="name">{{ s.nodeCode === 'start' ? s.createBy : (s.nodeName + (s.createBy ? '-' + s.createBy :
            '')) }}</text>
          <text class="time">{{ s.createTime }}</text>
        </view>
        <view class="desc">{{ s.nodeCode === 'start' ? '发起' : (s.approvalDesc + (s.message ? ':' : '') + s.message) }}
        </view>
      </view>
    </view>

  </view>
</template>
<script>
export default {
  name: 'FlowTimeline',
  props: {
    nodeList: { type: Array, default: () => [] },
    isEnd: { type: Boolean, default: false }
  },
  data() {
    return { renderNodeList: [] }
  },
  watch: {
    isEnd: {
      immediate: true,
      handler() {
        this.updateRenderNodeList()
      }
    }
  },
  methods: {
    updateRenderNodeList() {
      this.renderNodeList = [];
      let base = [...this.nodeList];
      console.log('updateRenderNodeList__base', base)
      console.log('updateRenderNodeList__this.isEnd', this.isEnd)
      if (this.isEnd) {
        const lastNode = base[base.length - 1] || {};
        console.log('updateRenderNodeList__lastNode', lastNode)
        const pass = lastNode.approval === 1;
        // 审批结果(1:通过;2:退回;3:撤回;4:反对;5:终止)
        base.push({ nodeName: pass ? '完成' : '结束', active: false, isFinish: pass });
      } else {
        if (base.length) {
          base[base.length - 1].active = true;
        }
      }
      this.renderNodeList = base.map(item => {
        return {
          approval: item.approval || 0,
          approvalDesc: item.approvalDesc || '',
          createBy: item.createBy || '',
          createTime: item.createTime || '',
          message: item.message || '',
          nodeCode: item.nodeCode || '',
          nodeName: item.nodeName || '',
          active: item.active || false,
          isFinish: item.approval === 1
        }
      }) || []
    }
  }
}
</script>
<style lang="scss" scoped>
.timeline {
  background: #fff;
  padding: 26rpx 32rpx;

  .node {
    position: relative;
    padding-left: 28rpx;
    margin-bottom: 8rpx;

    .dot {
      position: absolute;
      top: 14rpx;
      left: 0;
      width: 16rpx;
      height: 16rpx;
      border: 1px solid $theme-primary;
      border-radius: 50%;
      background: $theme-primary;

      &.active {
        background: #fff;
      }

      &.red {
        background: #D54941;
        border-color: #D54941;
      }
    }

    .line {
      position: absolute;
      top: 52rpx;
      left: 8rpx;
      bottom: 0;
      width: 2rpx;
      background: #E7E7E7;
      background: $theme-primary;
    }

    &:last-child {
      .line {
        background: transparent;
      }
    }

    .content {
      padding-left: 24rpx;
      padding-bottom: 32rpx;

      .row {
        display: flex;
        justify-content: space-between;
        margin-bottom: 8rpx;

        .name {
          color: rgba(0, 0, 0, 0.9);
          font-size: 28rpx;
          line-height: 44rpx;
        }

        .time {
          color: rgba(0, 0, 0, 0.4);
          font-size: 24rpx;
          flex-shrink: 0;
          line-height: 44rpx;
        }
      }

      .desc {
        color: rgba(0, 0, 0, 0.6);
        font-size: 24rpx;
        line-height: 40rpx;
      }

    }
  }
}
</style>