Files
superlink/api/common/duplicate_check.php
T

240 lines
9.1 KiB
PHP
Raw 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
/**
* 全局唯一性校验(2026-08-09)
* 手机号码 / 邮箱 / 身份证号码 / 企业注册号 / 社媒账号ID / 主页链接 / 企业名称
* 新增、修改时必须调用;重复时返回重复记录信息(供前端弹窗 + 跳转定位)
* 说明:
* - 手机/邮箱存在 social_accounts(platform=phone/email)
* - 社媒账号ID 同平台内唯一(wechat/douyin 等,不含 phone/email)
* - 主页链接 social_accounts.profile_url 全局唯一(非空才校验)
* - 企业名称 name_zh 或 display_name 任一相同即重复
*/
require_once __DIR__ . '/db.php';
/** 字段中文名 */
const DUP_LABELS = [
'phone' => '手机号码',
'email' => '邮箱',
'id_number' => '身份证号码',
'registration_number' => '企业注册号',
'account_id' => '社媒账号ID',
'profile_url' => '主页链接',
'company_name' => '企业名称',
];
/**
* 查询 social_accounts 重复记录(phone/email/account_id/profile_url 共用)
* @return array|null
*/
function findSocialDuplicate(PDO $pdo, $where, $params)
{
$sql =
"SELECT sa.id, sa.owner_type, sa.owner_id,
COALESCE(p.full_name, c.display_name) AS owner_name
FROM social_accounts sa
LEFT JOIN persons p ON p.id = sa.owner_id AND sa.owner_type = 'person'
LEFT JOIN companies c ON c.id = sa.owner_id AND sa.owner_type = 'company'
WHERE $where AND sa.is_active = 1
LIMIT 1";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$row = $stmt->fetch();
if (!$row) {
return null;
}
return $row;
}
/**
* 校验唯一性
* @param PDO $pdo
* @param string $type phone|email|id_number|registration_number|account_id|profile_url|company_name
* @param string $value 待校验值
* @param array $excludeIds 排除自身记录ID(编辑时;social_accounts 传其 id / persons 传 persons.id / companies 传 companies.id)
* @param string|null $platform account_id 类型时必传(同平台内唯一)
* @return array|null {label,value,table,id,owner_type,owner_id,name,owner_label,jump}
*/
function findDuplicate(PDO $pdo, $type, $value, $excludeIds = [], $platform = null)
{
$value = trim((string)$value);
if ($value === '') {
return null;
}
$excludeIds = array_values(array_filter(array_map('intval', (array)$excludeIds)));
$excludeSql = '';
$excludeParams = [];
if ($excludeIds) {
$excludeSql = ' AND id NOT IN (' . implode(',', $excludeIds) . ')';
}
switch ($type) {
case 'phone':
case 'email':
$row = findSocialDuplicate($pdo, "sa.platform = ? AND LOWER(sa.account_id) = LOWER(?)" . str_replace('id NOT IN', 'sa.id NOT IN', $excludeSql), array_merge([$type, $value], $excludeParams));
if (!$row) {
return null;
}
return [
'label' => $type === 'phone' ? '手机号码' : '邮箱',
'value' => $value,
'table' => 'social_accounts',
'id' => (int)$row['id'],
'owner_type' => $row['owner_type'],
'owner_id' => (int)$row['owner_id'],
'name' => $row['owner_name'] ?: ('#' . $row['owner_id']),
'owner_label'=> $row['owner_type'] === 'person' ? '人员' : '企业',
'jump' => 'media.html?id=' . (int)$row['id'],
];
case 'account_id':
// 社媒账号:同平台内唯一(phone/email 走专门校验)
if ($platform === null || in_array($platform, ['phone', 'email'], true)) {
return null;
}
$row = findSocialDuplicate($pdo, "sa.platform = ? AND LOWER(sa.account_id) = LOWER(?)" . str_replace('id NOT IN', 'sa.id NOT IN', $excludeSql), array_merge([$platform, $value], $excludeParams));
if (!$row) {
return null;
}
return [
'label' => '社媒账号ID',
'value' => $value,
'table' => 'social_accounts',
'id' => (int)$row['id'],
'owner_type' => $row['owner_type'],
'owner_id' => (int)$row['owner_id'],
'name' => $row['owner_name'] ?: ('#' . $row['owner_id']),
'owner_label'=> $row['owner_type'] === 'person' ? '人员' : '企业',
'jump' => 'media.html?id=' . (int)$row['id'],
];
case 'profile_url':
$row = findSocialDuplicate($pdo, "sa.profile_url = ? AND sa.profile_url <> ''" . str_replace('id NOT IN', 'sa.id NOT IN', $excludeSql), array_merge([$value], $excludeParams));
if (!$row) {
return null;
}
return [
'label' => '主页链接',
'value' => $value,
'table' => 'social_accounts',
'id' => (int)$row['id'],
'owner_type' => $row['owner_type'],
'owner_id' => (int)$row['owner_id'],
'name' => $row['owner_name'] ?: ('#' . $row['owner_id']),
'owner_label'=> $row['owner_type'] === 'person' ? '人员' : '企业',
'jump' => 'media.html?id=' . (int)$row['id'],
];
case 'id_number':
$stmt = $pdo->prepare("SELECT id, full_name FROM persons WHERE id_number = ? AND is_active = 1$excludeSql LIMIT 1");
$stmt->execute(array_merge([$value], $excludeParams));
$row = $stmt->fetch();
if (!$row) {
return null;
}
return [
'label' => '身份证号码',
'value' => $value,
'table' => 'persons',
'id' => (int)$row['id'],
'name' => $row['full_name'] ?: ('#' . $row['id']),
'jump' => 'person.html?id=' . (int)$row['id'],
];
case 'registration_number':
$stmt = $pdo->prepare("SELECT id, display_name FROM companies WHERE registration_number = ? AND is_active = 1$excludeSql LIMIT 1");
$stmt->execute(array_merge([$value], $excludeParams));
$row = $stmt->fetch();
if (!$row) {
return null;
}
return [
'label' => '企业注册号',
'value' => $value,
'table' => 'companies',
'id' => (int)$row['id'],
'name' => $row['display_name'] ?: ('#' . $row['id']),
'jump' => 'company.html?id=' . (int)$row['id'],
];
case 'company_name':
$stmt = $pdo->prepare("SELECT id, display_name FROM companies WHERE (name_zh = ? OR display_name = ?) AND is_active = 1$excludeSql LIMIT 1");
$stmt->execute(array_merge([$value, $value], $excludeParams));
$row = $stmt->fetch();
if (!$row) {
return null;
}
return [
'label' => '企业名称',
'value' => $value,
'table' => 'companies',
'id' => (int)$row['id'],
'name' => $row['display_name'] ?: ('#' . $row['id']),
'jump' => 'company.html?id=' . (int)$row['id'],
];
}
return null;
}
/**
* 校验单条账号(媒体模块扁平字段),返回所有重复项数组(空=无重复)
* @param PDO $pdo
* @param string $platform
* @param string $accountId
* @param string $profileUrl
* @param array $excludeIds
* @return array
*/
function checkSingleAccountDuplicate(PDO $pdo, $platform, $accountId, $profileUrl = '', $excludeIds = [])
{
$dups = [];
$platform = trim((string)$platform);
$accountId = trim((string)$accountId);
if ($platform !== '' && $accountId !== '') {
if ($platform === 'phone' || $platform === 'email') {
$dup = findDuplicate($pdo, $platform, $accountId, $excludeIds);
} else {
$dup = findDuplicate($pdo, 'account_id', $accountId, $excludeIds, $platform);
}
if ($dup) {
$dups[] = $dup;
}
}
$profileUrl = trim((string)$profileUrl);
if ($profileUrl !== '') {
$dup = findDuplicate($pdo, 'profile_url', $profileUrl, $excludeIds);
if ($dup) {
$dups[] = $dup;
}
}
return $dups;
}
/**
* 校验联系方式数组(persons/companies 的 contacts/accounts JSON),返回所有重复项数组(空=无重复)
* @param PDO $pdo
* @param array $accounts [{platform,account_id,profile_url,...}]
* @param array $excludeIds 整表替换时排除自身既有账号ID
* @return array
*/
function checkAccountsDuplicates(PDO $pdo, $accounts, $excludeIds = [])
{
$dups = [];
if (!is_array($accounts)) {
return $dups;
}
foreach ($accounts as $a) {
if (!is_array($a)) {
continue;
}
$dups = array_merge($dups, checkSingleAccountDuplicate(
$pdo,
$a['platform'] ?? '',
$a['account_id'] ?? '',
$a['profile_url'] ?? '',
$excludeIds
));
}
return $dups;
}