import type { RatingGradeItem } from '@/api/ratings' /** * 评级等级判定(纯函数,客户列表与评级弹窗共用同一口径)。 * * 规则:按 sort_order 升序取首个「min_score ≤ 总分」的等级,max_score 仅作 * 展示 —— 单边判定避免区间边界(如 75 分)在「≥75 且 ≤89」与「>74 且 <75」 * 两套写法间的重叠/遗漏歧义。 * * 后端 min_score 是字符串直出(分值红线:分值全程不进 float),比较前必须 * parseFloat 转数值,禁止字符串直接比大小("90.0" 的字典序比较会得出错误 * 结果)。无命中(总分低于全部下限)返回 null,由调用方展示未命中提示。 */ export function resolveGrade( grades: RatingGradeItem[], totalScore: number, ): RatingGradeItem | null { const ordered = [...grades].sort((a, b) => a.sort_order - b.sort_order) for (const grade of ordered) { if (totalScore >= parseFloat(grade.min_score)) { return grade } } return null } /** * 等级名称 → 色调后缀(客户列表的等级徽标用)。 * * 按名称首字母映射到体系语义色:A 优秀(绿)、B 良好(靛蓝)、C 合格 * (琥珀)、D 待改进(砖红);自定义等级名不在此列,落回中性灰 —— 等级 * 名称是业务可配置的,不能靠写死的枚举判定语义,未知即中性最安全。 */ export function gradeTone(gradeName: string): '' | 'ok' | 'lock' | 'wait' | 'reject' { const initial = gradeName.trim().charAt(0).toUpperCase() switch (initial) { case 'A': return 'ok' case 'B': return 'lock' case 'C': return 'wait' case 'D': return 'reject' default: return '' } }