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>
 |