Files

184 lines
6.1 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 人员人脉接口 GET /api/person/connections.php?person_id=X
* 列出与该人员相关的其他人员(交集:工作履历/家乡/毕业院校)
* - 同事:在 person_work_experiences 中任职过同一家公司
* - 老乡:家乡市级一致(如 湖南衡阳 vs 湖南衡阳;仅为湖南省不算)
* - 校友:毕业院校相同
* 亲密度(百分比):
* 老乡/校友/同事 各 +20;同一家公司任职次数≥2 +10;同事且入职年份一致 +10;
* 工作地点一致 +10;性别一致(均为男或均为女)+5;剩余 0~5 随机;
* 任何两人亲密度不得超过 99%(不能达到 100%)
* 入参:person_id(必填)/ limit(默认 50)
* 返回:{ list: [{id, full_name, phone, tags:[老乡,校友,同事], intimacy}] }
*/
require_once __DIR__ . '/../common/Api.php';
$pdo = Api::boot(['module' => 'person']);
$personId = (int)($_REQUEST['person_id'] ?? 0);
if ($personId <= 0) {
Response::error('参数错误', 400);
}
$limit = (int)($_REQUEST['limit'] ?? 50);
if ($limit <= 0 || $limit > 200) {
$limit = 50;
}
$pdo = DB::getInstance()->getPdo();
$stmt = $pdo->prepare("SELECT id, full_name, hometown, graduated_from, gender, work_location FROM persons WHERE id = ?");
$stmt->execute([$personId]);
$target = $stmt->fetch();
if (!$target) {
Response::error('人员不存在');
}
/** 省-市名称归一化:湖南省衡阳市 -> 湖南衡阳;新疆维吾尔自治区乌鲁木齐市 -> 新疆乌鲁木齐;北京市 -> 北京 */
function normalizeAreaName($s)
{
$s = trim((string)$s);
if ($s === '') {
return '';
}
$muni = ['北京市' => '北京', '天津市' => '天津', '上海市' => '上海', '重庆市' => '重庆'];
if (isset($muni[$s])) {
return $muni[$s];
}
// 自治区后缀(维吾尔/壮族/回族)及省后缀
$s = preg_replace('/(维吾尔|壮族|回族)?自治区$/', '', $s);
$s = str_replace('省', '', $s);
// 去掉末尾「市」
$s = preg_replace('/市$/', '', $s);
$s = str_replace('特别行政区', '', $s);
return $s;
}
$tHometown = normalizeAreaName($target['hometown']);
$tWorkLoc = normalizeAreaName($target['work_location']);
$tSchool = trim((string)$target['graduated_from']);
$tGender = $target['gender'];
$isGenderPair = ($tGender === '男' || $tGender === '女');
// 目标人员的任职公司集合:company_id => 入职年份
$expMap = []; // person_id => [ ['company_id'=>x,'sy'=>yyyy|null], ... ]
$targetComps = []; // company_id => sy
$stmt = $pdo->prepare(
"SELECT person_id, company_id, YEAR(start_date) AS sy
FROM person_work_experiences WHERE is_active = 1 AND person_id != ?"
);
$stmt->execute([$personId]);
$candIds = [];
foreach ($stmt as $row) {
$pid = (int)$row['person_id'];
$expMap[$pid][] = ['company_id' => (int)$row['company_id'], 'sy' => $row['sy'] !== null ? (int)$row['sy'] : null];
$candIds[$pid] = true;
}
$stmt = $pdo->prepare(
"SELECT company_id, YEAR(start_date) AS sy
FROM person_work_experiences WHERE is_active = 1 AND person_id = ?"
);
$stmt->execute([$personId]);
foreach ($stmt as $row) {
$targetComps[(int)$row['company_id']] = $row['sy'] !== null ? (int)$row['sy'] : null;
}
// 候选人员基本信息
$candList = $pdo->query(
"SELECT id, full_name, hometown, graduated_from, gender, work_location FROM persons WHERE id != $personId AND is_active = 1"
)->fetchAll();
// 手机号(常用优先)
$phones = [];
foreach ($pdo->query(
"SELECT owner_id, account_id FROM social_accounts
WHERE owner_type = 'person' AND platform = 'phone' AND is_active = 1
ORDER BY is_defult DESC, is_primary DESC, id DESC"
) as $row) {
if (!isset($phones[$row['owner_id']])) {
$phones[$row['owner_id']] = $row['account_id'];
}
}
$result = [];
foreach ($candList as $c) {
$tags = [];
$score = 0;
// 老乡:市级一致(归一化后整体相等即省市都一致)
$cHometown = normalizeAreaName($c['hometown']);
if ($tHometown !== '' && $cHometown !== '' && $tHometown === $cHometown) {
$tags[] = '老乡';
$score += 20;
}
// 校友
$cSchool = trim((string)$c['graduated_from']);
if ($tSchool !== '' && $cSchool !== '' && $tSchool === $cSchool) {
$tags[] = '校友';
$score += 20;
}
// 同事:任职公司交集
$shared = []; // company_id => [targetSy, candSy]
foreach (($expMap[$c['id']] ?? []) as $e) {
if (isset($targetComps[$e['company_id']])) {
$shared[$e['company_id']] = [$targetComps[$e['company_id']], $e['sy']];
}
}
if ($shared) {
$tags[] = '同事';
$score += 20;
// 同一家公司任职次数≥2(两家及以上共同任职公司)
if (count($shared) >= 2) {
$score += 10;
}
// 同事且入职年份一致
foreach ($shared as $pair) {
if ($pair[0] !== null && $pair[1] !== null && $pair[0] === $pair[1]) {
$score += 10;
break;
}
}
}
// 工作地点一致
$cWorkLoc = normalizeAreaName($c['work_location']);
if ($tWorkLoc !== '' && $cWorkLoc !== '' && $tWorkLoc === $cWorkLoc) {
$score += 10;
}
// 性别一致(均为男或均为女)
if ($isGenderPair && ($c['gender'] === '男' || $c['gender'] === '女') && $c['gender'] === $tGender) {
$score += 5;
}
// 至少有一种交集才进入人脉
if (!$tags) {
continue;
}
// 随机 0~5(剩余百分比),总亲密上限 99(不能达到 100%)
$score += mt_rand(0, 5);
$score = min(99, $score);
$result[] = [
'id' => (int)$c['id'],
'full_name' => $c['full_name'],
'phone' => $phones[$c['id']] ?? '',
'tags' => $tags,
'intimacy' => $score,
];
}
// 亲密度降序,其次按 id 升序
usort($result, function ($a, $b) {
if ($b['intimacy'] !== $a['intimacy']) {
return $b['intimacy'] - $a['intimacy'];
}
return $a['id'] - $b['id'];
});
$result = array_slice($result, 0, $limit);
Response::success(['list' => $result]);