<template>
  <view class="circle-progress" :style="{ width: size + 'rpx', height: size + 'rpx' }">
    <!-- 背景圆环 -->
    <canvas 
      :type="canvasType"
      class="progress-canvas"
      :style="{ width: size + 'rpx', height: size + 'rpx' }"
      :id="canvasId"
      :canvas-id="canvasId"
      @ready="onCanvasReady"
    ></canvas>
    
    <!-- 进度文字 -->
    <view class="progress-text" v-if="showText">
      <slot>
        <text class="text-value">{{ progress }}%</text>
      </slot>
    </view>
  </view>
</template>

<script>
export default {
  name: 'CircleProgress',
  
  props: {
    // 进度值（0-100）
    progress: {
      type: Number,
      default: 0,
      validator: value => value >= 0 && value <= 100
    },
    // 圆环大小
    size: {
      type: Number,
      default: 200
    },
    // 圆环宽度
    strokeWidth: {
      type: Number,
      default: 10
    },
    // 圆环颜色
    color: {
      type: String,
      default: '#FF4767'
    },
    // 背景圆环颜色
    backgroundColor: {
      type: String,
      default: '#F5F5F5'
    },
    // 是否显示进度文字
    showText: {
      type: Boolean,
      default: true
    },
    // 是否显示动画
    animation: {
      type: Boolean,
      default: true
    },
    // 动画时长（毫秒）
    duration: {
      type: Number,
      default: 1000
    }
  },
  
  data() {
    return {
      canvasId: 'circleProgress_' + Math.random().toString(36).substr(2, 9),
      ctx: null,
      canvas: null,
      animationFrame: null,
      currentProgress: 0,
      canvasType: '2d'
    }
  },
  
  watch: {
    progress: {
      handler(newVal) {
        if (this.animation) {
          this.animateProgress(newVal)
        } else {
          this.currentProgress = newVal
          this.drawProgress()
        }
      },
      immediate: true
    }
  },
  
  mounted() {
    // #ifdef H5
    this.canvasType = ''
    // #endif
    this.initCanvas()
  },
  
  beforeDestroy() {
    if (this.animationFrame) {
      cancelAnimationFrame(this.animationFrame)
    }
  },
  
  methods: {
    // 初始化画布
    async initCanvas() {
      const query = uni.createSelectorQuery().in(this)
      query.select(`#${this.canvasId}`)
        .fields({ node: true, size: true })
        .exec((res) => {
          if (!res[0]) return
          
          // #ifdef H5
          this.canvas = res[0].node || res[0].canvas
          if (!this.canvas) {
            this.canvas = document.getElementById(this.canvasId)
          }
          // #endif
          
          // #ifndef H5
          this.canvas = res[0].node
          // #endif
          
          if (!this.canvas) return
          
          this.ctx = this.canvas.getContext('2d')
          if (!this.ctx) return
          
          // 设置画布大小
          const dpr = uni.getSystemInfoSync().pixelRatio
          this.canvas.width = this.size * dpr
          this.canvas.height = this.size * dpr
          this.ctx.scale(dpr, dpr)
          
          // 设置初始进度
          this.currentProgress = this.progress
          // 绘制初始进度
          this.drawProgress()
        })
    },
    
    // 绘制进度
    drawProgress() {
      if (!this.ctx) return
      
      const center = this.size / 2
      const radius = (this.size - this.strokeWidth) / 2
      
      // 清空画布
      this.ctx.clearRect(0, 0, this.size, this.size)
      
      // 绘制背景圆环
      this.ctx.beginPath()
      this.ctx.arc(center, center, radius, 0, Math.PI * 2)
      this.ctx.strokeStyle = this.backgroundColor
      this.ctx.lineWidth = this.strokeWidth
      this.ctx.lineCap = 'round'
      this.ctx.stroke()
      
      // 绘制进度圆环
      if (this.currentProgress > 0) {
        const endAngle = (this.currentProgress / 100) * Math.PI * 2
        
        // 创建渐变色
        const gradient = this.ctx.createLinearGradient(0, 0, this.size, 0)
        gradient.addColorStop(0, this.color)
        gradient.addColorStop(1, this.color)
        
        this.ctx.beginPath()
        this.ctx.arc(center, center, radius, -Math.PI / 2, endAngle - Math.PI / 2)
        this.ctx.strokeStyle = gradient
        this.ctx.lineWidth = this.strokeWidth
        this.ctx.lineCap = 'round'
        this.ctx.stroke()
        
        // 添加发光效果
        this.ctx.shadowColor = this.color
        this.ctx.shadowBlur = 10
        this.ctx.stroke()
        this.ctx.shadowBlur = 0
      }
    },
    
    // 动画效果
    animateProgress(targetProgress) {
      if (this.animationFrame) {
        cancelAnimationFrame(this.animationFrame)
      }
      
      const startProgress = this.currentProgress
      const startTime = Date.now()
      
      // 使用缓动函数
      const easeOutQuart = (x) => {
        return 1 - Math.pow(1 - x, 4)
      }
      
      const animate = () => {
        const currentTime = Date.now()
        const elapsed = currentTime - startTime
        
        if (elapsed >= this.duration) {
          this.currentProgress = targetProgress
          this.drawProgress()
          return
        }
        
        const progress = easeOutQuart(elapsed / this.duration)
        this.currentProgress = startProgress + (targetProgress - startProgress) * progress
        this.drawProgress()
        
        this.animationFrame = requestAnimationFrame(animate)
      }
      
      animate()
    }
  }
}
</script>

<style>
.circle-progress {
  position: relative;
  display: inline-flex;
  justify-content: center;
  align-items: center;
}

.progress-canvas {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

.progress-text {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.text-value {
  font-size: 32rpx;
  color: #333333;
  font-weight: 500;
}

/* H5适配 */
/* #ifdef H5 */
.progress-canvas {
  transform: scale(1);
}
/* #endif */

/* APP适配 */
/* #ifdef APP-PLUS */
.progress-canvas {
  transform: scale(1);
}
/* #endif */

/* 小程序适配 */
/* #ifdef MP-WEIXIN */
.progress-canvas {
  transform: scale(1);
}
/* #endif */
</style> 