// 打卡日历的日期标记: 环形进度 (F-CL-06) // // 为什么是环而不是圆点: // 旧实现是 4px 小圆点, 只按状态上色 —— 3/5 和 5/5 都是同一个绿点, // 看不出"当天做到几成"。改成环形后 **弧长 = 当天完成比例**, 颜色表状态: // 0 < actual < expected -> 弧长按比例 (部分完成) // actual >= expected -> 整圈 (全部完成) // actual = 0 且 expected > 0 -> 只有底环 (未开始) // expected = 0 由父组件判断, 不渲染本组件 (当天没有应打卡项) // // 颜色分级 (4 档, 由 CSS 按 `.mv-day` 作用域上色, 各视图可各自调色板): // 小半 (ratio < 0.5) -> 红 // 大半 (0.5 <= r < 1) -> 橘 // 完成 (r = 1) -> 蓝 // 超额 -> 绿 // 注意: 服务端统计时把 actual 封顶在 expected (`Math.min(cnt, exp)`), // 所以 ratio 永远 <= 1, **超额只能靠 status === 'over' 判断**, 不能看比例。 const DEFAULT_SIZE = 30 const DEFAULT_STROKE = 2.5 /** 4 档分级: 小半 / 大半 / 完成 / 超额 */ function tierOf(status, p) { if (status === 'over') return 'over' if (status === 'full') return 'full' if (p <= 0) return 'empty' if (p >= 1) return 'full' return p < 0.5 ? 'low' : 'high' } export default function DayRing({ status = 'partial', ratio = 0, size = DEFAULT_SIZE, stroke = DEFAULT_STROKE, }) { const p = Math.max(0, Math.min(1, Number(ratio) || 0)) const tier = tierOf(status, p) const r = (size - stroke) / 2 const c = 2 * Math.PI * r const half = size / 2 return ( ) }