267 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <div class="summary7">
 | 
						|
    <div class="left">
 | 
						|
      <div class="el-progress-circle" :style="{height: width + 'px', width: width + 'px'}">
 | 
						|
        <svg viewBox="0 0 100 100">
 | 
						|
          <defs>
 | 
						|
            <linearGradient id="blue" x1="0%" y1="0%" x2="100%" y2="0%">
 | 
						|
                <stop offset="0%" style="stop-color:#243D93;stop-opacity:1" />
 | 
						|
                <stop offset="100%" style="stop-color:#4EFFDC;stop-opacity:1" />
 | 
						|
            </linearGradient>
 | 
						|
          </defs>
 | 
						|
          <path
 | 
						|
            class="el-progress-circle__track"
 | 
						|
            :d="trackPath"
 | 
						|
            stroke="#464C63"
 | 
						|
            :stroke-width="relativeStrokeWidth"
 | 
						|
            fill="none"
 | 
						|
            :style="trailPathStyle"></path>
 | 
						|
          <path
 | 
						|
            class="el-progress-circle__path"
 | 
						|
            :d="trackPath"
 | 
						|
            :stroke="stroke"
 | 
						|
            fill="none"
 | 
						|
            stroke-linecap="butt"
 | 
						|
            :stroke-width="percentage ? relativeStrokeWidth : 0"
 | 
						|
            :style="circlePathStyle"></path>
 | 
						|
        </svg>
 | 
						|
        <div class="pointer">
 | 
						|
          <div class="pointer-round"></div>
 | 
						|
          <div class="pointer-circle"></div>
 | 
						|
          <div class="pointer-line" :style="{transform: `rotate(${rotateDeg}deg)`}"></div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
    <div class="middle">
 | 
						|
      <p><span>{{ data[0][value] }}</span></p>
 | 
						|
      <h2>{{ data[0][keys] }}</h2>
 | 
						|
    </div>
 | 
						|
    <div class="right">
 | 
						|
      <div class="summary7-item" v-for="(item, index) in data" :key="index" v-if="index < 4 && index !== 0">
 | 
						|
        <h2>{{ item[keys] }}</h2>
 | 
						|
        <p>{{ item[value] }}</p>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
  export default {
 | 
						|
    name: 'Summary7',
 | 
						|
 | 
						|
    props: {
 | 
						|
      data: {
 | 
						|
        type: Array,
 | 
						|
        default: () => []
 | 
						|
      },
 | 
						|
 | 
						|
      keys: {
 | 
						|
        type: String,
 | 
						|
        default: 'key'
 | 
						|
      },
 | 
						|
 | 
						|
      value: {
 | 
						|
        type: String,
 | 
						|
        default: 'value'
 | 
						|
      },
 | 
						|
    },
 | 
						|
 | 
						|
    data () {
 | 
						|
      return {
 | 
						|
        width: 70,
 | 
						|
        strokeWidth: 8
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    computed: {
 | 
						|
      rotateDeg () {
 | 
						|
        return this.percentage / 100 * 270 + (360 * 0.25) / 2 + 90
 | 
						|
      },
 | 
						|
 | 
						|
      relativeStrokeWidth() {
 | 
						|
        return (this.strokeWidth / this.width * 100).toFixed(1);
 | 
						|
      },
 | 
						|
 | 
						|
      percentage () {
 | 
						|
        if (this.data.length) {
 | 
						|
          return typeof this.data[0][this.value] === 'string' ? Number(this.data[0][this.value].replace('%', '')) : this.data[0][this.value]
 | 
						|
        }
 | 
						|
 | 
						|
        return 0
 | 
						|
      },
 | 
						|
 | 
						|
      radius() {
 | 
						|
        return parseInt(50 - parseFloat(this.relativeStrokeWidth) / 2, 10);
 | 
						|
      },
 | 
						|
      perimeter() {
 | 
						|
        return 2 * Math.PI * this.radius;
 | 
						|
      },
 | 
						|
      trackPath() {
 | 
						|
        const radius = this.radius;
 | 
						|
        const isDashboard = true
 | 
						|
        return `
 | 
						|
          M 50 50
 | 
						|
          m 0 ${isDashboard ? '' : '-'}${radius}
 | 
						|
          a ${radius} ${radius} 0 1 1 0 ${isDashboard ? '-' : ''}${radius * 2}
 | 
						|
          a ${radius} ${radius} 0 1 1 0 ${isDashboard ? '' : '-'}${radius * 2}
 | 
						|
          `;
 | 
						|
      },
 | 
						|
      strokeDashoffset() {
 | 
						|
        const offset = -1 * this.perimeter * (1 - this.rate) / 2;
 | 
						|
        return `${offset}px`;
 | 
						|
      },
 | 
						|
      trailPathStyle() {
 | 
						|
        return {
 | 
						|
          strokeDasharray: `${(this.perimeter * this.rate)}px, ${this.perimeter}px`,
 | 
						|
          strokeDashoffset: this.strokeDashoffset
 | 
						|
        };
 | 
						|
      },
 | 
						|
      circlePathStyle() {
 | 
						|
        return {
 | 
						|
          strokeDasharray: `${this.perimeter * this.rate * (this.percentage / 100) }px, ${this.perimeter}px`,
 | 
						|
          strokeDashoffset: this.strokeDashoffset,
 | 
						|
          transition: 'stroke-dasharray 0.6s ease 0s, stroke 0.6s ease'
 | 
						|
        };
 | 
						|
      },
 | 
						|
      stroke() {
 | 
						|
        return 'url(#blue)';
 | 
						|
      },
 | 
						|
      rate() {
 | 
						|
        return 0.75
 | 
						|
      },
 | 
						|
    },
 | 
						|
 | 
						|
    methods: {
 | 
						|
      getCurrentColor(percentage) {
 | 
						|
        if (typeof this.color === 'function') {
 | 
						|
          return this.color(percentage);
 | 
						|
        } else if (typeof this.color === 'string') {
 | 
						|
          return this.color;
 | 
						|
        } else {
 | 
						|
          return this.getLevelColor(percentage);
 | 
						|
        }
 | 
						|
      },
 | 
						|
    }
 | 
						|
  }
 | 
						|
</script>
 | 
						|
 | 
						|
<style lang="scss" scoped>
 | 
						|
  .summary7 {
 | 
						|
    display: flex;
 | 
						|
    align-items: center;
 | 
						|
    justify-content: space-between;
 | 
						|
    width: 380px;
 | 
						|
    height: 124px;
 | 
						|
    padding: 0 44px;
 | 
						|
    background: url(./../asset/summary6-bg.svg);
 | 
						|
    background-size: 100% 100%;
 | 
						|
 | 
						|
    .el-progress-circle {
 | 
						|
      position: relative;
 | 
						|
 | 
						|
      .pointer-round {
 | 
						|
        position: absolute;
 | 
						|
        left: 50%;
 | 
						|
        top: 50%;
 | 
						|
        z-index: 1;
 | 
						|
        width: 20px;
 | 
						|
        height: 20px;
 | 
						|
        border: 1px solid #2E69FF;
 | 
						|
        border-radius: 50%;
 | 
						|
        transform: translate(-50%, -50%);
 | 
						|
      }
 | 
						|
 | 
						|
      .pointer-circle {
 | 
						|
        position: absolute;
 | 
						|
        left: 50%;
 | 
						|
        top: 50%;
 | 
						|
        z-index: 1;
 | 
						|
        width: 8px;
 | 
						|
        height: 8px;
 | 
						|
        background: #FDDD60;
 | 
						|
        border-radius: 50%;
 | 
						|
        transform: translate(-50%, -50%);
 | 
						|
      }
 | 
						|
 | 
						|
      .pointer-line {
 | 
						|
        position: absolute;
 | 
						|
        left: 50%;
 | 
						|
        top: 50%;
 | 
						|
        z-index: 1;
 | 
						|
        width: 35px;
 | 
						|
        height: 1px;
 | 
						|
        background: #FDDD60;
 | 
						|
        transform: rotate(90deg);
 | 
						|
        transform-origin: 0 0 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    div {
 | 
						|
      box-sizing: border-box;
 | 
						|
    }
 | 
						|
 | 
						|
    .left {
 | 
						|
      position: relative;
 | 
						|
      top: 5px;
 | 
						|
    }
 | 
						|
 | 
						|
    .middle {
 | 
						|
      margin: 0 16px;
 | 
						|
      p {
 | 
						|
        display: flex;
 | 
						|
        align-items: baseline;
 | 
						|
        justify-content: center;
 | 
						|
        font-size: 36px;
 | 
						|
        font-weight: bold;
 | 
						|
        color: #FFFFFF;
 | 
						|
        line-height: 32px;
 | 
						|
        text-align: center;
 | 
						|
        background-image: linear-gradient(180deg, #FFFFFF 0%, #FFDD8C 100%);
 | 
						|
        -webkit-background-clip: text;
 | 
						|
        -webkit-text-fill-color: transparent;
 | 
						|
 | 
						|
        i {
 | 
						|
          font-size: 16px;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      h2 {
 | 
						|
        display: flex;
 | 
						|
        align-items: baseline;
 | 
						|
        font-size: 14px;
 | 
						|
        font-weight: bold;
 | 
						|
        color: #FFFFFF;
 | 
						|
        text-align: center;
 | 
						|
        background-image: linear-gradient(180deg, #FFFFFF 0%, #C7C7C7 100%);
 | 
						|
        -webkit-background-clip: text;
 | 
						|
        -webkit-text-fill-color: transparent;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    .right {
 | 
						|
    }
 | 
						|
 | 
						|
    .summary7-item {
 | 
						|
      display: flex;
 | 
						|
      position: relative;
 | 
						|
      align-items: center;
 | 
						|
 | 
						|
      h2 {
 | 
						|
        flex: 1;
 | 
						|
        line-height: 24px;
 | 
						|
        margin-right: 8px;
 | 
						|
        color: #A8D7F3;
 | 
						|
        font-size: 12px;
 | 
						|
        font-weight: normal;
 | 
						|
        text-align: right;
 | 
						|
      }
 | 
						|
 | 
						|
      p {
 | 
						|
        font-weight: 700;
 | 
						|
        font-size: 15px;
 | 
						|
        color: #fff;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
</style>
 |