getResource(); if (empty($resources)) { Log::write('没有可分配的资源'); return $this->getSuccessResult([ 'allocated' => 0, 'message' => '没有可分配的资源' ]); } // 获取销售人员 $salesmen = $this->getSalesman(); if (empty($salesmen)) { Log::write('没有可用的销售人员'); return $this->getSuccessResult([ 'allocated' => 0, 'message' => '没有可用的销售人员' ]); } // 分配资源 $result = $this->allocateResource($resources, $salesmen); return $this->getSuccessResult([ 'allocated' => $result['allocated'] ?? 0, 'updated' => $result['updated'] ?? 0, 'created' => $result['created'] ?? 0, 'total_resources' => count($resources), 'total_salesmen' => count($salesmen) ]); } /** * 获取销售人员(按角色ID为6或7的人员,支持校区优先和主管兜底) * @param int|null $campus_id 校区ID,用于优先分配 * @return array 销售人员列表 */ public function getSalesman(?int $campus_id = null) { Log::write('获取销售人员' . ($campus_id ? ',优先校区ID:' . $campus_id : '')); // 获取所有角色ID为6或7的人员 $all_salesmen = CampusPersonRole::where('role_id', 'in', [6, 7]) ->where('deleted_at', 0) ->field('person_id, role_id, campus_id') ->select() ->toArray(); if (empty($all_salesmen)) { Log::write('未找到销售人员'); return []; } // 获取人员详细信息 $person_ids = array_column($all_salesmen, 'person_id'); $personnel_info = Personnel::whereIn('id', $person_ids) ->field('id, name, status') ->where('status', 1) // 只获取在职人员 ->select() ->toArray(); $personnel_map = array_column($personnel_info, null, 'id'); // 过滤在职人员并整理数据 $valid_salesmen = []; foreach ($all_salesmen as $salesman) { if (isset($personnel_map[$salesman['person_id']])) { $salesman['name'] = $personnel_map[$salesman['person_id']]['name']; $valid_salesmen[] = $salesman; } } if (empty($valid_salesmen)) { Log::write('未找到在职销售人员'); return []; } // 获取每个销售人员当前拥有的资源数量(使用新表) foreach ($valid_salesmen as &$salesman) { $resourceCount = ResourceAssignment::where('assignee_type', 'user') ->where('assignee_id', $salesman['person_id']) ->count(); $salesman['resource_count'] = $resourceCount; } // 如果指定了校区,优先分配给该校区的销售人员 if ($campus_id) { $campus_salesmen = array_filter($valid_salesmen, function($salesman) use ($campus_id) { return $salesman['campus_id'] == $campus_id; }); if (!empty($campus_salesmen)) { // 校区内销售人员按资源数量排序 array_multisort(array_column($campus_salesmen, 'resource_count'), SORT_ASC, $campus_salesmen); // 其他销售人员(主管兜底)按资源数量排序 $other_salesmen = array_filter($valid_salesmen, function($salesman) use ($campus_id) { return $salesman['campus_id'] != $campus_id; }); if (!empty($other_salesmen)) { array_multisort(array_column($other_salesmen, 'resource_count'), SORT_ASC, $other_salesmen); // 主管优先(角色ID=7) usort($other_salesmen, function($a, $b) { if ($a['role_id'] == 7 && $b['role_id'] != 7) return -1; if ($a['role_id'] != 7 && $b['role_id'] == 7) return 1; return $a['resource_count'] - $b['resource_count']; }); } Log::write('找到' . count($campus_salesmen) . '个校区销售人员,' . count($other_salesmen) . '个其他销售人员'); // 返回校区优先,主管兜底的列表 return array_merge($campus_salesmen, $other_salesmen); } } // 没有指定校区或没有校区销售人员,按主管优先排序 usort($valid_salesmen, function($a, $b) { // 主管优先(角色ID=7) if ($a['role_id'] == 7 && $b['role_id'] != 7) return -1; if ($a['role_id'] != 7 && $b['role_id'] == 7) return 1; // 相同角色按资源数量排序 return $a['resource_count'] - $b['resource_count']; }); Log::write('找到' . count($valid_salesmen) . '个销售人员,主管优先排序'); return $valid_salesmen; } /** * 获取待分配的资源(使用新表结构) * @return array 待分配资源列表 */ public function getResource() { Log::write('获取待分配资源'); // 方法1:获取新表中没有分配记录的资源 $customer_resources = CustomerResources::alias('cr') ->leftJoin('school_resource_assignment ra', 'cr.id = ra.resource_id') ->whereNull('ra.resource_id') ->field('cr.id as resource_id, cr.campus_id, cr.name, cr.phone_number') ->select() ->toArray(); if (empty($customer_resources)) { Log::write('未找到待分配资源'); return []; } Log::write('找到' . count($customer_resources) . '个待分配资源'); return $customer_resources; } /** * 按照销售人员的资源拥有情况分配资源(使用新表结构) * @param array $resources 待分配的资源列表 * @param array $salesmen 销售人员列表 */ public function allocateResource($resources, $salesmen) { Log::write('按照销售人员的资源拥有情况分配资源'); if (empty($resources) || empty($salesmen)) { Log::write('没有资源或销售人员,无法分配'); return [ 'allocated' => 0, 'updated' => 0, 'created' => 0 ]; } // 记录分配结果 $allocations = []; $createdCount = 0; // 开始分配 foreach ($resources as $resource) { // 重新获取销售人员的资源数量排序,确保每次分配都是给最少资源的人 $currentSalesmen = $this->refreshSalesmenResourceCount($salesmen, $resource['campus_id']); if (empty($currentSalesmen)) { Log::write('没有可用的销售人员'); break; } // 选择最优销售人员 $targetSalesman = $currentSalesmen[0]; // 使用新表创建分配记录 try { Db::startTrans(); // 检查是否已存在分配记录 $existingAssignment = ResourceAssignment::where('resource_id', $resource['resource_id']) ->where('assignee_type', 'user') ->where('assignee_id', $targetSalesman['person_id']) ->find(); if ($existingAssignment) { Log::write('资源ID ' . $resource['resource_id'] . ' 已分配给销售人员 ' . $targetSalesman['name'] . ',跳过'); Db::commit(); continue; } // 创建新的分配记录 $assignmentData = [ 'resource_id' => $resource['resource_id'], 'assignee_type' => 'user', // 精确分配到人 'assignee_id' => $targetSalesman['person_id'], 'is_primary' => 0, // 非主责分配 'assigned_by' => 0, // 系统自动分配 'assigned_at' => date('Y-m-d H:i:s'), 'campus_id' => $resource['campus_id'], // 使用资源的校区 'assigned_source' => 'auto_allocation' // 标记为自动分配 ]; $assignment = ResourceAssignment::create($assignmentData); if ($assignment) { $createdCount++; Log::write('成功分配资源ID:' . $resource['resource_id'] . ' 给销售人员:' . $targetSalesman['name'] . ' (ID:' . $targetSalesman['person_id'] . ')'); } Db::commit(); } catch (\Exception $e) { Db::rollback(); Log::write('资源分配失败,资源ID:' . $resource['resource_id'] . ',错误:' . $e->getMessage()); } } Log::write('成功分配 ' . $createdCount . ' 个资源'); return [ 'allocated' => $createdCount, 'updated' => 0, 'created' => $createdCount ]; } /** * 刷新销售人员的资源数量并重新排序(使用新表结构) * @param array $salesmen 销售人员列表 * @param int|null $campus_id 资源所属校区ID * @return array 更新后的销售人员列表 */ private function refreshSalesmenResourceCount($salesmen, ?int $campus_id = null) { if (empty($salesmen)) { return []; } foreach ($salesmen as &$salesman) { // 使用新表查询资源数量 $resourceCount = ResourceAssignment::where('assignee_type', 'user') ->where('assignee_id', $salesman['person_id']) ->count(); $salesman['resource_count'] = $resourceCount; } // 如果指定了校区,按校区优先和资源数量重新排序 if ($campus_id) { $campus_salesmen = array_filter($salesmen, function($salesman) use ($campus_id) { return $salesman['campus_id'] == $campus_id; }); if (!empty($campus_salesmen)) { // 校区内销售人员按资源数量排序 array_multisort(array_column($campus_salesmen, 'resource_count'), SORT_ASC, $campus_salesmen); // 其他销售人员按主管优先和资源数量排序 $other_salesmen = array_filter($salesmen, function($salesman) use ($campus_id) { return $salesman['campus_id'] != $campus_id; }); if (!empty($other_salesmen)) { usort($other_salesmen, function($a, $b) { // 主管优先(角色ID=7) if ($a['role_id'] == 7 && $b['role_id'] != 7) return -1; if ($a['role_id'] != 7 && $b['role_id'] == 7) return 1; // 相同角色按资源数量排序 return $a['resource_count'] - $b['resource_count']; }); } // 返回校区优先,主管兜底的列表 return array_merge($campus_salesmen, $other_salesmen); } } // 没有校区或没有校区销售人员,按主管优先和资源数量排序 usort($salesmen, function($a, $b) { // 主管优先(角色ID=7) if ($a['role_id'] == 7 && $b['role_id'] != 7) return -1; if ($a['role_id'] != 7 && $b['role_id'] == 7) return 1; // 相同角色按资源数量排序 return $a['resource_count'] - $b['resource_count']; }); return $salesmen; } }