This commit is contained in:
xman 2025-07-22 16:49:30 +08:00
parent ceace800d0
commit 7ddb2ac593

View File

@ -246,92 +246,67 @@ class Kpidispatcher extends Backend
$max_score = $template->max_score??100;
if(!empty($data)){
foreach ($data as &$datum){
//利润率 = 总业绩/总成效额
$datum->performance_rate = $this->_calc($datum->performance,$datum->total,4,true);
//转化率 = 完单数 / 总订单数
$datum->trans_rate = $this->_calc($datum->finish_num,$datum->count_num,4,true);
//变现值 = 总业绩 / 总订单数
$datum->cash_value = $this->_calc($datum->performance,$datum->count_num,2);
//客单利润 = 总利润 / 完单数
$datum->performance_avg = $this->_calc($datum->performance,$datum->finish_num,2);
//客单价 = 总成效额 / 完单数
$datum->total_avg = $this->_calc($datum->total,$datum->finish_num,2);
if(!empty($datum->dispatch_admin_id)){
$datum->admin_user = Admin::where('id',$datum->dispatch_admin_id)->value('nickname')??'系统';
}else{
$datum->admin_user = '系统';
}
foreach ($data as &$datum) {
// 常规字段计算
$datum->performance_rate = $this->_calc($datum->performance, $datum->total, 4, true);
$datum->trans_rate = $this->_calc($datum->finish_num, $datum->count_num, 4, true);
$datum->cash_value = $this->_calc($datum->performance, $datum->count_num, 2);
$datum->performance_avg = $this->_calc($datum->performance, $datum->finish_num, 2);
$datum->total_avg = $this->_calc($datum->total, $datum->finish_num, 2);
$datum->avg_time_diff = $this->_calc($datum->avg_time_diff, 3600, 4);
// 管理员名称
//派单员数量不多,循环中查
$datum->admin_user = !empty($datum->dispatch_admin_id)
? Admin::where('id', $datum->dispatch_admin_id)->value('nickname') ?? '系统'
: '系统';
$datum->id = $datum->dispatch_admin_id;
// 初始化 KPI 总分
$kpi_total = 0;
//kpi
//转化率
$datum->zhl_score = 0;
$datum->zhl_target_value = $kpiItem[KpiItem::ATTR_ZHL]['target_value']??0;
$datum->unit = '';
if(!empty($kpiItem[KpiItem::ATTR_ZHL])){
$datum->zhl_score = $this->_kpi_score($datum->trans_rate,$kpiItem[KpiItem::ATTR_ZHL]);
$kpi_total += $datum->zhl_score;
//$datum->zhl_unit = $kpiItem[KpiItem::ATTR_ZHL]['unit'];
}
//利润率
$datum->lrl_score = 0;
$datum->lrl_target_value = $kpiItem[KpiItem::ATTR_LRL]['target_value']??0;
if (!empty($kpiItem[KpiItem::ATTR_LRL])) {
$datum->lrl_score = $this->_kpi_score($datum->performance_rate, $kpiItem[KpiItem::ATTR_LRL]);
$kpi_total += $datum->lrl_score;
//$datum->lrl_unit = $kpiItem[KpiItem::ATTR_LRL]['unit'];
}
// 定义 KPI 计算配置
$kpiMap = [
KpiItem::ATTR_ZHL => ['field' => 'trans_rate', 'score_field' => 'zhl_score', 'target_field' => 'zhl_target_value'],
KpiItem::ATTR_LRL => ['field' => 'performance_rate','score_field' => 'lrl_score', 'target_field' => 'lrl_target_value'],
KpiItem::ATTR_PDSX => ['field' => 'avg_time_diff', 'score_field' => 'pdsx_score', 'target_field' => 'pdsx_target_value', 'reverse' => true],
KpiItem::ATTR_PCCGL => ['field' => 'succ_rate', 'score_field' => 'pccgl_score', 'target_field' => 'pccgl_target_value'],
KpiItem::ATTR_LRSFS => ['field' => 'worker_num', 'score_field' => 'lrsfs_score', 'target_field' => 'lrsfs_target_value'],
];
//派单时效
$datum->pdsx_score = 0;
$datum->pdsx_target_value = $kpiItem[KpiItem::ATTR_PDSX]['target_value']??0; //秒
if (!empty($kpiItem[KpiItem::ATTR_PDSX])) {
$datum->pdsx_score = $this->_kpi_score($datum->avg_time_diff, $kpiItem[KpiItem::ATTR_PDSX],$fande=true);
$kpi_total += $datum->pdsx_score;
//$datum->pdsx_unit = $kpiItem[KpiItem::ATTR_PDSX]['unit'];
}
//派单成功率
// 单独处理 success rate派单成功率
$datum->succ_rate = $this->_calc($datum->finish_num, $datum->count_num, 4, true);
$datum->pccgl_score = 0;
$datum->pccgl_target_value = $kpiItem[KpiItem::ATTR_PCCGL]['target_value']??0;
if (!empty($kpiItem[KpiItem::ATTR_PCCGL])) {
$datum->pccgl_score = $this->_kpi_score($datum->succ_rate, $kpiItem[KpiItem::ATTR_PCCGL]);
$kpi_total += $datum->pccgl_score;
//$datum->pccgl_unit = $kpiItem[KpiItem::ATTR_PCCGL]['unit'];
}
//录单师傅数
$datum->lrsfs_score = 0;
$datum->lrsfs_target_value = $kpiItem[KpiItem::ATTR_LRSFS]['target_value']??0;
$datum->worker_num = $datum->worker_num ?? 0;
if (!empty($kpiItem[KpiItem::ATTR_LRSFS])) {
$datum->lrsfs_score = $this->_kpi_score($datum->worker_num, $kpiItem[KpiItem::ATTR_LRSFS]);
$kpi_total += $datum->lrsfs_score;
// 批量处理 KPI 项
foreach ($kpiMap as $attr => $conf) {
$item = $kpiItem[$attr] ?? null;
$datum->{$conf['score_field']} = 0;
$datum->{$conf['target_field']} = $item['target_value'] ?? 0;
if ($item) {
$reverse = $conf['reverse'] ?? false;
$value = $datum->{$conf['field']};
$score = $this->_kpi_score($value, $item, $reverse);
$datum->{$conf['score_field']} = $score;
$kpi_total += $score;
}
}
// KPI 总分和比值
$datum->kpi_total = bcadd($kpi_total, 0, 2);
$datum->kpi_value = $this->_calc($kpi_total, $template->score ?: 1, 2);
// KPI 奖金
if ($datum->kpi_value <= 0) {
$datum->kpi_money = 0;
} else {
$datum->kpi_money = bcmul($datum->performance,$datum->kpi_value,4);
$money = bcmul($datum->performance, $datum->kpi_value, 4);
$datum->kpi_money = $money > 0 ? bcdiv($money, 100, 2) : 0;
}
if($datum->kpi_money <= 0){
$datum->kpi_money = 0;
}else{
$datum->kpi_money = bcdiv($datum->kpi_money,100,2);
}
}
$newData[] = $datum->toArray();
}
}
@ -367,34 +342,30 @@ class Kpidispatcher extends Backend
private function _kpi_score($num, $item, $fande = false)
{
//完成值/目标值*单个指标分*权重
$target = $item['target_value'] ?? 1;
$target = $target == 0 ? 1 : $target; // 避免除以0
if($item['target_value'] == 0){
$item['target_value'] = 1;
}
// 计算得分比例
if ($fande) {
//哦哦 如果定的是10分钟完成的为15分钟则1-(15-10/10
//这个还要区分是超过10还是小于10超过10了就上面的没超过就是1 + 10-完成值)/10
if($num > $item['target_value']){
$rate = bcdiv(($num-$item['target_value']),$item['target_value'],4);
$rate = bcsub(1,$rate,4);
$diff = bcsub($num, $target, 4);
$rate = bcdiv(abs($diff), $target, 4);
// 方向判断:小于目标加分,超过目标扣分
$rate = $num > $target
? bcsub(1, $rate, 4)
: bcadd(1, $rate, 4);
} else {
$rate = bcdiv(($item['target_value']-$num),$item['target_value'],4);
$rate = bcadd(1,$rate,4);
}
}else{
$rate = bcdiv($num,$item['target_value'],4);
$rate = bcdiv($num, $target, 4);
}
// 得分 = 比例 × 指标分数 × 权重
$score = bcmul($item['score'], $rate, 4);
$score = bcmul($score,$item['pivot']['rate']/100,2);
$weight = isset($item['pivot']['rate']) ? $item['pivot']['rate'] : 100;
$score = bcmul($score, bcdiv($weight, 100, 4), 2);
if($score<= 0){
$score = 0;
return max($score, 0); // 保证非负
}
return $score;
}