0806
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
/**
|
||||
* 国际电话国家区号表(区号 => 中文国籍/地区名)
|
||||
* 用于海外手机号码归属地识别(对应 DeepSeek 方案一中 phonenumbers 库的国家识别能力)。
|
||||
* 覆盖常用国家/地区;未收录区号将返回"未知"。
|
||||
*/
|
||||
return [
|
||||
// 1 区:北美
|
||||
'1' => '美国/加拿大',
|
||||
// 7 区:俄罗斯/哈萨克斯坦
|
||||
'7' => '俄罗斯',
|
||||
// 20 区
|
||||
'20' => '埃及',
|
||||
// 27 区:南非
|
||||
'27' => '南非',
|
||||
// 30-39 区:欧洲
|
||||
'30' => '希腊',
|
||||
'31' => '荷兰',
|
||||
'32' => '比利时',
|
||||
'33' => '法国',
|
||||
'34' => '西班牙',
|
||||
'36' => '匈牙利',
|
||||
'39' => '意大利',
|
||||
// 40-49 区
|
||||
'40' => '罗马尼亚',
|
||||
'41' => '瑞士',
|
||||
'43' => '奥地利',
|
||||
'44' => '英国',
|
||||
'45' => '丹麦',
|
||||
'46' => '瑞典',
|
||||
'47' => '挪威',
|
||||
'48' => '波兰',
|
||||
'49' => '德国',
|
||||
// 50-59 区
|
||||
'51' => '秘鲁',
|
||||
'52' => '墨西哥',
|
||||
'53' => '古巴',
|
||||
'54' => '阿根廷',
|
||||
'55' => '巴西',
|
||||
'56' => '智利',
|
||||
'57' => '哥伦比亚',
|
||||
'58' => '委内瑞拉',
|
||||
// 60-69 区
|
||||
'60' => '马来西亚',
|
||||
'61' => '澳大利亚',
|
||||
'62' => '印度尼西亚',
|
||||
'63' => '菲律宾',
|
||||
'64' => '新西兰',
|
||||
'65' => '新加坡',
|
||||
'66' => '泰国',
|
||||
// 7x 区:俄罗斯等(已在上方)
|
||||
// 80-89 区
|
||||
'81' => '日本',
|
||||
'82' => '韩国',
|
||||
'84' => '越南',
|
||||
'86' => '中国',
|
||||
// 90-99 区
|
||||
'90' => '土耳其',
|
||||
'91' => '印度',
|
||||
'92' => '巴基斯坦',
|
||||
'93' => '阿富汗',
|
||||
'94' => '斯里兰卡',
|
||||
'95' => '缅甸',
|
||||
'96' => '约旦',
|
||||
'97' => '叙利亚',
|
||||
'98' => '伊朗',
|
||||
// 其他常见
|
||||
'211' => '南苏丹',
|
||||
'212' => '摩洛哥',
|
||||
'213' => '阿尔及利亚',
|
||||
'216' => '突尼斯',
|
||||
'218' => '利比亚',
|
||||
'220' => '冈比亚',
|
||||
'221' => '塞内加尔',
|
||||
'222' => '毛里塔尼亚',
|
||||
'223' => '马里',
|
||||
'224' => '几内亚',
|
||||
'225' => '科特迪瓦',
|
||||
'226' => '布基纳法索',
|
||||
'227' => '尼日尔',
|
||||
'228' => '多哥',
|
||||
'229' => '贝宁',
|
||||
'230' => '毛里求斯',
|
||||
'231' => '利比里亚',
|
||||
'232' => '塞拉利昂',
|
||||
'233' => '加纳',
|
||||
'234' => '尼日利亚',
|
||||
'235' => '乍得',
|
||||
'236' => '中非',
|
||||
'237' => '喀麦隆',
|
||||
'238' => '佛得角',
|
||||
'239' => '圣多美和普林西比',
|
||||
'240' => '赤道几内亚',
|
||||
'241' => '加蓬',
|
||||
'242' => '刚果(布)',
|
||||
'243' => '刚果(金)',
|
||||
'244' => '安哥拉',
|
||||
'245' => '几内亚比绍',
|
||||
'246' => '迪戈加西亚',
|
||||
'248' => '塞舌尔',
|
||||
'249' => '苏丹',
|
||||
'250' => '卢旺达',
|
||||
'251' => '埃塞俄比亚',
|
||||
'252' => '索马里',
|
||||
'253' => '吉布提',
|
||||
'254' => '肯尼亚',
|
||||
'255' => '坦桑尼亚',
|
||||
'256' => '乌干达',
|
||||
'257' => '布隆迪',
|
||||
'258' => '莫桑比克',
|
||||
'260' => '赞比亚',
|
||||
'261' => '马达加斯加',
|
||||
'262' => '留尼汪/马约特',
|
||||
'263' => '津巴布韦',
|
||||
'264' => '纳米比亚',
|
||||
'265' => '马拉维',
|
||||
'266' => '莱索托',
|
||||
'267' => '博茨瓦纳',
|
||||
'268' => '斯威士兰',
|
||||
'269' => '科摩罗',
|
||||
'290' => '圣赫勒拿',
|
||||
'291' => '厄立特里亚',
|
||||
'297' => '阿鲁巴',
|
||||
'298' => '法罗群岛',
|
||||
'299' => '格陵兰',
|
||||
'350' => '直布罗陀',
|
||||
'351' => '葡萄牙',
|
||||
'352' => '卢森堡',
|
||||
'353' => '爱尔兰',
|
||||
'354' => '冰岛',
|
||||
'355' => '阿尔巴尼亚',
|
||||
'356' => '马耳他',
|
||||
'357' => '塞浦路斯',
|
||||
'358' => '芬兰',
|
||||
'359' => '保加利亚',
|
||||
'370' => '立陶宛',
|
||||
'371' => '拉脱维亚',
|
||||
'372' => '爱沙尼亚',
|
||||
'373' => '摩尔多瓦',
|
||||
'374' => '亚美尼亚',
|
||||
'375' => '白俄罗斯',
|
||||
'376' => '安道尔',
|
||||
'377' => '摩纳哥',
|
||||
'378' => '圣马力诺',
|
||||
'380' => '乌克兰',
|
||||
'381' => '塞尔维亚',
|
||||
'382' => '黑山',
|
||||
'383' => '科索沃',
|
||||
'385' => '克罗地亚',
|
||||
'386' => '斯洛文尼亚',
|
||||
'387' => '波黑',
|
||||
'389' => '北马其顿',
|
||||
'420' => '捷克',
|
||||
'421' => '斯洛伐克',
|
||||
'423' => '列支敦士登',
|
||||
'500' => '福克兰群岛',
|
||||
'501' => '伯利兹',
|
||||
'502' => '危地马拉',
|
||||
'503' => '萨尔瓦多',
|
||||
'504' => '洪都拉斯',
|
||||
'505' => '尼加拉瓜',
|
||||
'506' => '哥斯达黎加',
|
||||
'507' => '巴拿马',
|
||||
'508' => '圣皮埃尔和密克隆',
|
||||
'509' => '海地',
|
||||
'590' => '瓜德罗普',
|
||||
'591' => '玻利维亚',
|
||||
'592' => '圭亚那',
|
||||
'593' => '厄瓜多尔',
|
||||
'594' => '法属圭亚那',
|
||||
'595' => '巴拉圭',
|
||||
'596' => '马提尼克',
|
||||
'597' => '苏里南',
|
||||
'598' => '乌拉圭',
|
||||
'599' => '加勒比荷兰',
|
||||
'670' => '东帝汶',
|
||||
'672' => '南极领地',
|
||||
'673' => '文莱',
|
||||
'674' => '瑙鲁',
|
||||
'675' => '巴布亚新几内亚',
|
||||
'676' => '汤加',
|
||||
'677' => '所罗门群岛',
|
||||
'678' => '瓦努阿图',
|
||||
'679' => '斐济',
|
||||
'680' => '帕劳',
|
||||
'681' => '瓦利斯和富图纳',
|
||||
'682' => '库克群岛',
|
||||
'683' => '纽埃',
|
||||
'685' => '萨摩亚',
|
||||
'686' => '基里巴斯',
|
||||
'687' => '新喀里多尼亚',
|
||||
'688' => '图瓦卢',
|
||||
'689' => '法属波利尼西亚',
|
||||
'690' => '托克劳',
|
||||
'691' => '密克罗尼西亚',
|
||||
'692' => '马绍尔群岛',
|
||||
'850' => '朝鲜',
|
||||
'852' => '中国香港',
|
||||
'853' => '中国澳门',
|
||||
'855' => '柬埔寨',
|
||||
'856' => '老挝',
|
||||
'880' => '孟加拉国',
|
||||
'886' => '中国台湾',
|
||||
'960' => '马尔代夫',
|
||||
'961' => '黎巴嫩',
|
||||
'962' => '约旦',
|
||||
'963' => '叙利亚',
|
||||
'964' => '伊拉克',
|
||||
'965' => '科威特',
|
||||
'966' => '沙特阿拉伯',
|
||||
'967' => '也门',
|
||||
'968' => '阿曼',
|
||||
'970' => '巴勒斯坦',
|
||||
'971' => '阿联酋',
|
||||
'972' => '以色列',
|
||||
'973' => '巴林',
|
||||
'974' => '卡塔尔',
|
||||
'975' => '不丹',
|
||||
'976' => '蒙古',
|
||||
'977' => '尼泊尔',
|
||||
'992' => '塔吉克斯坦',
|
||||
'993' => '土库曼斯坦',
|
||||
'994' => '阿塞拜疆',
|
||||
'995' => '格鲁吉亚',
|
||||
'996' => '吉尔吉斯斯坦',
|
||||
'998' => '乌兹别克斯坦',
|
||||
];
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* 数据字典接口 GET /api/common/dicts.php
|
||||
* 参数:type=country|area|industry|certificate|source_channel|all(默认 all)
|
||||
* 返回各字典表启用中的数据,供前端下拉/联动使用。
|
||||
* 数据来源:官方 Excel 生成的种子数据(见 sql/dict_seed.sql),不依赖任何第三方接口。
|
||||
*/
|
||||
require_once __DIR__ . '/db.php';
|
||||
require_once __DIR__ . '/response.php';
|
||||
require_once __DIR__ . '/auth.php';
|
||||
|
||||
requireLogin();
|
||||
|
||||
$type = trim($_REQUEST['type'] ?? 'all');
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
|
||||
$data = [];
|
||||
|
||||
if ($type === 'all' || $type === 'country') {
|
||||
$data['countries'] = $pdo->query(
|
||||
"SELECT id, code, name FROM date_dict_country WHERE is_active = 1 ORDER BY sort_order, id"
|
||||
)->fetchAll();
|
||||
}
|
||||
if ($type === 'all' || $type === 'area') {
|
||||
$data['areas'] = $pdo->query(
|
||||
"SELECT id, code, name, parent_code FROM date_dict_area WHERE is_active = 1 ORDER BY sort_order, id"
|
||||
)->fetchAll();
|
||||
}
|
||||
if ($type === 'all' || $type === 'industry') {
|
||||
$data['industries'] = $pdo->query(
|
||||
"SELECT id, code, name, parent_code FROM date_dict_industry WHERE is_active = 1 ORDER BY sort_order, id"
|
||||
)->fetchAll();
|
||||
}
|
||||
if ($type === 'all' || $type === 'certificate') {
|
||||
$data['certificates'] = $pdo->query(
|
||||
"SELECT id, code, name FROM date_dict_certificate WHERE is_active = 1 ORDER BY sort_order, id"
|
||||
)->fetchAll();
|
||||
}
|
||||
if ($type === 'all' || $type === 'source_channel') {
|
||||
$data['source_channels'] = $pdo->query(
|
||||
"SELECT id, name FROM source_channels WHERE is_active = 1 ORDER BY sort_order, id"
|
||||
)->fetchAll();
|
||||
}
|
||||
|
||||
Response::success($data);
|
||||
@@ -14,6 +14,7 @@ const COMPANY_FIELDS = [
|
||||
'industry' => 's', 'industry_subdivision' => 's',
|
||||
'latest_employee_count' => 'i', 'latest_annual_revenue' => 's',
|
||||
'is_listed' => 'i', 'stock_code' => 's', 'website' => 's',
|
||||
'source_channel' => 's', 'source_detail' => 's',
|
||||
];
|
||||
|
||||
/** 人员表可写入字段白名单 */
|
||||
@@ -21,12 +22,13 @@ const PERSON_FIELDS = [
|
||||
'union_id' => 's', 'full_name' => 's', 'gender' => 's', 'nationality' => 's',
|
||||
'id_type' => 's', 'id_number' => 's', 'education' => 's', 'graduated_from' => 's',
|
||||
'hometown' => 's', 'work_location' => 's',
|
||||
'source_channel' => 's', 'source_detail' => 's',
|
||||
];
|
||||
|
||||
/** 媒体(社交账号)表可写入字段白名单 */
|
||||
const MEDIA_FIELDS = [
|
||||
'owner_type' => 's', 'owner_id' => 'i', 'platform' => 's', 'account_id' => 's',
|
||||
'profile_url' => 's', 'remark' => 's', 'is_primary' => 'i',
|
||||
'profile_url' => 's', 'remark' => 's', 'is_primary' => 'i', 'is_defult' => 'i',
|
||||
];
|
||||
|
||||
/** 媒体商业属性表可写入字段白名单 */
|
||||
@@ -173,7 +175,7 @@ function saveCompanyCertifications($pdo, $companyId, $certifications)
|
||||
return;
|
||||
}
|
||||
|
||||
$valid = $pdo->prepare("SELECT id FROM certification_types WHERE id = ?");
|
||||
$valid = $pdo->prepare("SELECT id FROM date_dict_certificate WHERE id = ?");
|
||||
$ins = $pdo->prepare(
|
||||
"INSERT INTO company_certifications
|
||||
(company_id, certification_type_id, certificate_number, issue_date, expiry_date)
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
/**
|
||||
* 手机号码归属地识别接口 GET /api/common/phone_geo.php?phone=13812345678
|
||||
* 需求:录入手机号码时自动识别归属地
|
||||
* - 国内号码:识别"国家-省-市"(如 中国-广东省-深圳市)
|
||||
* - 港澳台: 标注为"中国香港"/"中国澳门"/"中国台湾"
|
||||
* - 海外号码:识别"国籍"(如 美国)
|
||||
* 实现方案(参考 DeepSeek 方案一:phonenumbers + phone 双库组合):
|
||||
* - 国内省市:使用 phone.dat 数据库(Google libphonenumber 同源号段数据,见 data/phone.dat)
|
||||
* - 国际号码:内置国家区号表识别国籍
|
||||
* 返回:{ country, province, city, label, found }
|
||||
* label 示例:"中国-广东省-深圳市" / "中国香港" / "美国"
|
||||
*/
|
||||
require_once __DIR__ . '/db.php';
|
||||
require_once __DIR__ . '/response.php';
|
||||
require_once __DIR__ . '/auth.php';
|
||||
|
||||
/**
|
||||
* 接口入口:仅当作为 HTTP 接口直接访问时执行(便于函数被 require 复用/测试)
|
||||
*/
|
||||
if (isset($_SERVER['SCRIPT_FILENAME']) && realpath($_SERVER['SCRIPT_FILENAME']) === __FILE__) {
|
||||
requireLogin();
|
||||
|
||||
$phone = trim($_REQUEST['phone'] ?? '');
|
||||
if ($phone === '') {
|
||||
Response::error('参数错误:缺少 phone', 400);
|
||||
}
|
||||
|
||||
Response::success(detectPhoneLocation($phone));
|
||||
}
|
||||
|
||||
/* ==================== 归属地识别核心 ==================== */
|
||||
|
||||
/**
|
||||
* 解析号码归属地
|
||||
* @param string $phone 原始号码(可含 + / 空格 / 短横线)
|
||||
* @return array
|
||||
*/
|
||||
function detectPhoneLocation($phone)
|
||||
{
|
||||
$digits = preg_replace('/[^\d]/', '', $phone);
|
||||
$hasPlus = strpos($phone, '+') === 0;
|
||||
|
||||
// 处理国际前缀:+86 / 0086 / 86 开头统一识别
|
||||
// 0086 开头 → 转为 86 开头
|
||||
if (strpos($digits, '00') === 0) {
|
||||
$digits = substr($digits, 2);
|
||||
$hasPlus = true;
|
||||
}
|
||||
|
||||
// 1) 港澳台特殊标注
|
||||
$special = specialRegion($digits);
|
||||
if ($special !== null) {
|
||||
return ['country' => $special, 'province' => '', 'city' => '', 'label' => $special, 'found' => true];
|
||||
}
|
||||
|
||||
// 2) 中国大陆号码:+86/0086 开头 或 11位以 1 开头
|
||||
if (isChinaMobile($digits, $hasPlus)) {
|
||||
$geo = lookupChinaPhoneDat($digits);
|
||||
if ($geo !== null) {
|
||||
return [
|
||||
'country' => '中国',
|
||||
'province' => $geo['province'],
|
||||
'city' => $geo['city'],
|
||||
'label' => '中国-' . $geo['province'] . ($geo['city'] && $geo['city'] !== $geo['province'] ? '-' . $geo['city'] : ''),
|
||||
'found' => true,
|
||||
];
|
||||
}
|
||||
return ['country' => '中国', 'province' => '', 'city' => '', 'label' => '中国', 'found' => false];
|
||||
}
|
||||
|
||||
// 3) 海外号码:识别国籍(国家区号表)
|
||||
$country = lookupCountryByCode($digits);
|
||||
if ($country !== null) {
|
||||
return ['country' => $country, 'province' => '', 'city' => '', 'label' => $country, 'found' => true];
|
||||
}
|
||||
|
||||
return ['country' => '', 'province' => '', 'city' => '', 'label' => '未知', 'found' => false];
|
||||
}
|
||||
|
||||
/** 港澳台特殊识别 */
|
||||
function specialRegion($digits)
|
||||
{
|
||||
// 852 香港 / 853 澳门 / 886 台湾(号码 8-9 位)
|
||||
if (strpos($digits, '852') === 0 && strlen($digits) >= 11) return '中国香港';
|
||||
if (strpos($digits, '853') === 0 && strlen($digits) >= 11) return '中国澳门';
|
||||
if (strpos($digits, '886') === 0 && strlen($digits) >= 12) return '中国台湾';
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 是否中国大陆手机号 */
|
||||
function isChinaMobile($digits, $hasPlus)
|
||||
{
|
||||
// +86 或 0086 开头(去除前缀后为 11 位 1 开头)
|
||||
if (strpos($digits, '86') === 0 && strlen($digits) === 13) {
|
||||
return preg_match('/^861[3-9]\d{9}$/', $digits) === 1;
|
||||
}
|
||||
// 纯 11 位 1 开头(无国际前缀)
|
||||
if (!$hasPlus && strlen($digits) === 11 && $digits[0] === '1') {
|
||||
return preg_match('/^1[3-9]\d{9}$/', $digits) === 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 使用 phone.dat 查询国内省市 */
|
||||
function lookupChinaPhoneDat($digits)
|
||||
{
|
||||
static $loader = null;
|
||||
if ($loader === null) {
|
||||
$loader = new PhoneDatLoader(__DIR__ . '/../../data/phone.dat');
|
||||
}
|
||||
// 提取 11 位号码中的前 7 位号段(如 1381234);带 86 前缀先去前缀
|
||||
$local = preg_replace('/^86/', '', $digits);
|
||||
$prefix7 = substr($local, 0, 7);
|
||||
if (strlen($prefix7) !== 7 || !preg_match('/^\d{7}$/', $prefix7)) {
|
||||
return null;
|
||||
}
|
||||
return $loader->find($prefix7);
|
||||
}
|
||||
|
||||
/** 海外号码:国家区号表识别国籍 */
|
||||
function lookupCountryByCode($digits)
|
||||
{
|
||||
static $map = null;
|
||||
if ($map === null) {
|
||||
$map = require __DIR__ . '/country_codes.php';
|
||||
}
|
||||
// 依次尝试 3 位 / 2 位 / 1 位区号
|
||||
for ($len = 3; $len >= 1; $len--) {
|
||||
$code = substr($digits, 0, $len);
|
||||
if (isset($map[$code])) {
|
||||
return $map[$code];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ==================== phone.dat 解析器(PHP 移植) ==================== */
|
||||
|
||||
/**
|
||||
* phone.dat 文件解析器
|
||||
* 文件格式(与 Python phone 库一致):
|
||||
* - 头部:4字节版本号 + 4字节首条记录偏移
|
||||
* - 记录:每条 9 字节 = 4字节号段(int) + 4字节数据偏移(int) + 1字节号码类型
|
||||
* - 数据区:省份|城市|邮编|区号 (竖线分隔,\0 结尾)
|
||||
*/
|
||||
class PhoneDatLoader
|
||||
{
|
||||
private $buf;
|
||||
private $firstOffset;
|
||||
private $count;
|
||||
|
||||
public function __construct($file)
|
||||
{
|
||||
$this->buf = file_get_contents($file);
|
||||
if ($this->buf === false || strlen($this->buf) < 8) {
|
||||
$this->buf = '';
|
||||
$this->firstOffset = 0;
|
||||
$this->count = 0;
|
||||
return;
|
||||
}
|
||||
$head = unpack('a4version/ioffset', substr($this->buf, 0, 8));
|
||||
$this->firstOffset = $head['offset'];
|
||||
$this->count = (int)((strlen($this->buf) - $this->firstOffset) / 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 7 位号段查询
|
||||
* @param string $prefix7 如 "1381234"
|
||||
* @return array|null ['province'=>, 'city'=>, 'zip_code'=>, 'area_code'=>, 'phone_type'=>]
|
||||
*/
|
||||
public function find($prefix7)
|
||||
{
|
||||
if ($this->count <= 0 || !preg_match('/^\d{7}$/', (string)$prefix7)) {
|
||||
return null;
|
||||
}
|
||||
$intPhone = (int)$prefix7;
|
||||
$left = 0;
|
||||
$right = $this->count;
|
||||
$buflen = strlen($this->buf);
|
||||
|
||||
while ($left <= $right) {
|
||||
$middle = (int)(($left + $right) / 2);
|
||||
$offset = $this->firstOffset + $middle * 9;
|
||||
if ($offset >= $buflen) {
|
||||
return null;
|
||||
}
|
||||
$rec = unpack('iprefix/irecord_offset/Ctype', substr($this->buf, $offset, 9));
|
||||
if ($rec['prefix'] > $intPhone) {
|
||||
$right = $middle - 1;
|
||||
} elseif ($rec['prefix'] < $intPhone) {
|
||||
$left = $middle + 1;
|
||||
} else {
|
||||
$content = $this->readRecord($rec['record_offset']);
|
||||
if ($content === null) {
|
||||
return null;
|
||||
}
|
||||
$parts = explode('|', $content);
|
||||
return [
|
||||
'province' => $parts[0] ?? '',
|
||||
'city' => $parts[1] ?? '',
|
||||
'zip_code' => $parts[2] ?? '',
|
||||
'area_code' => $parts[3] ?? '',
|
||||
'phone_type' => $this->typeName($rec['type']),
|
||||
];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function readRecord($offset)
|
||||
{
|
||||
$end = strpos($this->buf, "\x00", $offset);
|
||||
if ($end === false) {
|
||||
return null;
|
||||
}
|
||||
return substr($this->buf, $offset, $end - $offset);
|
||||
}
|
||||
|
||||
private function typeName($no)
|
||||
{
|
||||
$map = [
|
||||
1 => '移动', 2 => '联通', 3 => '电信',
|
||||
4 => '电信虚拟运营商', 5 => '联通虚拟运营商', 6 => '移动虚拟运营商',
|
||||
7 => '广电', 8 => '广电虚拟运营商',
|
||||
];
|
||||
return $map[$no] ?? '未知';
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
/**
|
||||
* 认证类型字典接口 GET /api/company/cert_types.php
|
||||
* 返回启用中的认证类型(如:瞪羚企业、国家高新技术企业等),供编辑弹窗下拉使用
|
||||
* 数据源:date_dict_certificate(原 certification_types,v1.0.16 改名)
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
@@ -10,6 +11,6 @@ require_once __DIR__ . '/../common/auth.php';
|
||||
checkPermission('company');
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
$types = $pdo->query("SELECT id, name FROM certification_types WHERE is_active = 1 ORDER BY sort_order, id")->fetchAll();
|
||||
$types = $pdo->query("SELECT id, name FROM date_dict_certificate WHERE is_active = 1 ORDER BY sort_order, id")->fetchAll();
|
||||
|
||||
Response::success(['types' => $types]);
|
||||
|
||||
+13
-7
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* 企业详情接口 GET /api/company/detail.php?id=1
|
||||
* 返回企业主表信息 + 关联数据(产品品类/需求/文档/财务)
|
||||
* 返回企业主表信息 + 关联数据(产品品类/文档/财务/资质/联系方式)
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
@@ -26,9 +26,6 @@ if (!$company) {
|
||||
$products = $pdo->prepare("SELECT id, category_name, category_description, is_core, is_active FROM company_products WHERE company_id = ? AND is_active = 1");
|
||||
$products->execute([$id]);
|
||||
|
||||
$needs = $pdo->prepare("SELECT id, contact_person, need_category, target_product_category, application_scenario, description, is_valid, created_at FROM company_needs WHERE company_id = ? ORDER BY id DESC");
|
||||
$needs->execute([$id]);
|
||||
|
||||
$docs = $pdo->prepare(
|
||||
"SELECT cd.id, cd.doc_name, cd.storage_path, cd.file_type, cd.publish_date, cd.is_active
|
||||
FROM company_documents cd
|
||||
@@ -53,13 +50,22 @@ $certs = $pdo->prepare(
|
||||
"SELECT cc.certification_type_id, ct.name AS certification_name, cc.certificate_number,
|
||||
cc.issue_date, cc.expiry_date
|
||||
FROM company_certifications cc
|
||||
INNER JOIN certification_types ct ON ct.id = cc.certification_type_id
|
||||
INNER JOIN date_dict_certificate ct ON ct.id = cc.certification_type_id
|
||||
WHERE cc.company_id = ?
|
||||
ORDER BY ct.sort_order, ct.id"
|
||||
);
|
||||
$certs->execute([$id]);
|
||||
|
||||
$certTypes = $pdo->query("SELECT id, name FROM certification_types WHERE is_active = 1 ORDER BY sort_order, id")->fetchAll();
|
||||
$certTypes = $pdo->query("SELECT id, name FROM date_dict_certificate WHERE is_active = 1 ORDER BY sort_order, id")->fetchAll();
|
||||
|
||||
// 联系方式:social_accounts 中属于该公司的记录(仅展示,无修改/删除入口)
|
||||
$accounts = $pdo->prepare(
|
||||
"SELECT id, platform, account_id, profile_url, remark, is_primary, is_defult, is_active, created_at
|
||||
FROM social_accounts
|
||||
WHERE owner_type = 'company' AND owner_id = ?
|
||||
ORDER BY is_defult DESC, is_primary DESC, id DESC"
|
||||
);
|
||||
$accounts->execute([$id]);
|
||||
|
||||
// 关联联系人(工作经历 + 联系方式)
|
||||
$contacts = $pdo->prepare(
|
||||
@@ -79,11 +85,11 @@ $contacts->execute([$id, $id]);
|
||||
Response::success([
|
||||
'company' => $company,
|
||||
'products' => $products->fetchAll(),
|
||||
'needs' => $needs->fetchAll(),
|
||||
'documents' => $docs->fetchAll(),
|
||||
'financials' => $financials->fetchAll(),
|
||||
'relations' => $relations->fetchAll(),
|
||||
'contacts' => $contacts->fetchAll(),
|
||||
'accounts' => $accounts->fetchAll(),
|
||||
'certifications' => $certs->fetchAll(),
|
||||
'certification_types' => $certTypes,
|
||||
]);
|
||||
|
||||
@@ -60,10 +60,10 @@ $stmt = $pdo->prepare(
|
||||
pwe.job_level, pwe.start_date, pwe.end_date, pwe.is_current,
|
||||
(SELECT sa.account_id FROM social_accounts sa
|
||||
WHERE sa.owner_type = 'person' AND sa.owner_id = p.id AND sa.platform = 'phone' AND sa.is_active = 1
|
||||
ORDER BY sa.is_primary DESC LIMIT 1) AS phone,
|
||||
ORDER BY sa.is_defult DESC, sa.is_primary DESC LIMIT 1) AS phone,
|
||||
(SELECT sa.account_id FROM social_accounts sa
|
||||
WHERE sa.owner_type = 'person' AND sa.owner_id = p.id AND sa.platform = 'email' AND sa.is_active = 1
|
||||
ORDER BY sa.is_primary DESC LIMIT 1) AS email
|
||||
ORDER BY sa.is_defult DESC, sa.is_primary DESC LIMIT 1) AS email
|
||||
FROM person_work_experiences pwe
|
||||
INNER JOIN persons p ON p.id = pwe.person_id
|
||||
WHERE $whereSql
|
||||
|
||||
@@ -32,7 +32,7 @@ $stmt = $pdo->prepare(
|
||||
"SELECT id, name_zh, name_en, business_role, country, registration_number,
|
||||
address, legal_representative, industry, industry_subdivision, website,
|
||||
registered_capital, established_date, latest_employee_count, latest_annual_revenue,
|
||||
is_listed, stock_code, created_at
|
||||
is_listed, stock_code, source_channel, source_detail, created_at
|
||||
FROM companies WHERE id IN ($in) AND is_active = 1 ORDER BY id DESC"
|
||||
);
|
||||
$stmt->execute($idList);
|
||||
@@ -44,14 +44,14 @@ header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename="companies_' . date('Ymd_His') . '.csv"');
|
||||
echo "\xEF\xBB\xBF"; // UTF-8 BOM,便于 Excel 直接打开
|
||||
$out = fopen('php://output', 'w');
|
||||
fputcsv($out, ['ID', '公司名称', '英文名称', '业务角色', '国家/地区', '注册号', '地址', '法人', '行业', '行业细分', '官网', '注册资本', '成立日期', '员工数', '年营收', '是否上市', '股票代码', '创建时间']);
|
||||
fputcsv($out, ['ID', '公司名称', '英文名称', '业务角色', '国家/地区', '注册号', '地址', '法人', '行业', '行业细分', '官网', '注册资本', '成立日期', '员工数', '年营收', '是否上市', '股票代码', '来源渠道', '来源详情', '创建时间']);
|
||||
foreach ($list as $r) {
|
||||
fputcsv($out, [
|
||||
$r['id'], $r['name_zh'], $r['name_en'], $r['business_role'],
|
||||
$r['country'], $r['registration_number'], $r['address'], $r['legal_representative'],
|
||||
$r['industry'], $r['industry_subdivision'], $r['website'], $r['registered_capital'],
|
||||
$r['established_date'], $r['latest_employee_count'], $r['latest_annual_revenue'],
|
||||
$r['is_listed'], $r['stock_code'], date('Y-m-d', strtotime($r['created_at'])),
|
||||
$r['is_listed'], $r['stock_code'], $r['source_channel'], $r['source_detail'], date('Y-m-d', strtotime($r['created_at'])),
|
||||
]);
|
||||
}
|
||||
fclose($out);
|
||||
|
||||
@@ -36,6 +36,7 @@ $map = [
|
||||
'industry' => 'industry', 'industry_subdivision' => 'industry_subdivision', 'website' => 'website',
|
||||
'registered_capital' => 'registered_capital', 'established_date' => 'established_date',
|
||||
'is_listed' => 'is_listed', 'stock_code' => 'stock_code',
|
||||
'source_channel' => 'source_channel', 'source_detail' => 'source_detail',
|
||||
];
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
@@ -46,8 +47,8 @@ $stmt = $pdo->prepare(
|
||||
"INSERT INTO companies
|
||||
(name_zh, name_en, display_name, business_role, country, registration_number,
|
||||
address, legal_form, legal_representative, industry, industry_subdivision, website,
|
||||
registered_capital, established_date, is_listed, stock_code)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
|
||||
registered_capital, established_date, is_listed, stock_code, source_channel, source_detail)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
|
||||
);
|
||||
|
||||
while (($row = fgetcsv($handle)) !== false) {
|
||||
@@ -72,6 +73,7 @@ while (($row = fgetcsv($handle)) !== false) {
|
||||
$rec['industry'] ?? null, $rec['industry_subdivision'] ?? null, $rec['website'] ?? null,
|
||||
$rec['registered_capital'] ?? null, $rec['established_date'],
|
||||
($rec['is_listed'] ?? 0) ? 1 : 0, $rec['stock_code'] ?? null,
|
||||
$rec['source_channel'] ?? null, $rec['source_detail'] ?? null,
|
||||
]);
|
||||
$inserted++;
|
||||
} catch (Exception $e) {
|
||||
|
||||
@@ -55,7 +55,7 @@ $stmt = $pdo->prepare(
|
||||
"SELECT id, name_zh, name_en, display_name, business_role, country, registration_number,
|
||||
address, legal_representative, industry, industry_subdivision, website,
|
||||
latest_employee_count, latest_annual_revenue, is_listed, stock_code,
|
||||
is_active, created_at, updated_at
|
||||
source_channel, source_detail, is_active, created_at, updated_at
|
||||
FROM companies
|
||||
WHERE $whereSql
|
||||
ORDER BY id DESC
|
||||
|
||||
@@ -32,7 +32,7 @@ $whereSql = implode(' AND ', $where);
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT sa.id, sa.owner_type, sa.owner_id, sa.platform, sa.account_id, sa.profile_url, sa.remark,
|
||||
"SELECT sa.id, sa.owner_type, sa.owner_id, sa.platform, sa.account_id, sa.profile_url, sa.remark, sa.is_defult,
|
||||
mca.account_level, mca.content_categories, mca.follower_count, mca.avg_read_count,
|
||||
mca.certification_type, sa.created_at,
|
||||
CASE sa.owner_type
|
||||
@@ -52,11 +52,11 @@ header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename="media_' . date('Ymd_His') . '.csv"');
|
||||
echo "\xEF\xBB\xBF";
|
||||
$out = fopen('php://output', 'w');
|
||||
fputcsv($out, ['ID', '归属类型', '归属ID', '归属名称', '平台', '账号', '主页链接', '备注', '等级', '内容领域', '粉丝数', '平均阅读', '认证类型', '创建时间']);
|
||||
fputcsv($out, ['ID', '归属类型', '归属ID', '归属名称', '平台', '账号', '主页链接', '备注', '是否常用', '等级', '内容领域', '粉丝数', '平均阅读', '认证类型', '创建时间']);
|
||||
foreach ($list as $r) {
|
||||
fputcsv($out, [
|
||||
$r['id'], $r['owner_type'], $r['owner_id'], $r['owner_name'], $r['platform'],
|
||||
$r['account_id'], $r['profile_url'], $r['remark'], $r['account_level'],
|
||||
$r['account_id'], $r['profile_url'], $r['remark'], $r['is_defult'] ? '常用' : '备用', $r['account_level'],
|
||||
$r['content_categories'], $r['follower_count'], $r['avg_read_count'],
|
||||
$r['certification_type'], $r['created_at'],
|
||||
]);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* 媒体数据 CSV 导入接口 POST /api/media/import.php (multipart/form-data, 字段名 file)
|
||||
* CSV 表头:owner_type,owner_id,platform,account_id,profile_url,remark,is_primary,
|
||||
* CSV 表头:owner_type,owner_id,platform,account_id,profile_url,remark,is_primary,is_defult,
|
||||
* account_level,content_categories,follower_count,avg_read_count,certification_type
|
||||
* owner_type 为 person/company 时 owner_id 也可填对应名称(display_name/full_name),自动解析为ID。
|
||||
*/
|
||||
@@ -26,8 +26,8 @@ $header = str_getcsv(trim($first));
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
$insAccount = $pdo->prepare(
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, remark, is_primary, is_active)
|
||||
VALUES (?,?,?,?,?,?,?,1)"
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, remark, is_primary, is_defult, is_active)
|
||||
VALUES (?,?,?,?,?,?,?,?,1)"
|
||||
);
|
||||
$insAttr = $pdo->prepare(
|
||||
"INSERT INTO media_commercial_attributes
|
||||
@@ -75,6 +75,7 @@ while (($row = fgetcsv($handle)) !== false) {
|
||||
$insAccount->execute([
|
||||
$ownerType, $ownerId, $rec['platform'], $rec['account_id'],
|
||||
$rec['profile_url'] ?? null, $rec['remark'] ?? null, !empty($rec['is_primary']) ? 1 : 0,
|
||||
!empty($rec['is_defult']) ? 1 : 0,
|
||||
]);
|
||||
$newId = (int)$pdo->lastInsertId();
|
||||
if (!empty($rec['account_level']) || !empty($rec['certification_type'])) {
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ $total = (int)$stmt->fetchColumn();
|
||||
$offset = ($page - 1) * $limit;
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT sa.id, sa.owner_type, sa.owner_id, sa.platform, sa.account_id, sa.profile_url,
|
||||
sa.remark, sa.is_primary, sa.is_active, sa.created_at,
|
||||
sa.remark, sa.is_primary, sa.is_defult, sa.is_active, sa.created_at,
|
||||
mca.account_level, mca.content_categories, mca.follower_count, mca.avg_read_count,
|
||||
mca.certification_type, mca.special_requirements, mca.media_remark,
|
||||
CASE sa.owner_type
|
||||
|
||||
+4
-4
@@ -34,18 +34,18 @@ if ((int)$chk->fetchColumn() > 0) {
|
||||
$pdo->prepare("INSERT INTO persons $sql")->execute($params);
|
||||
$newId = (int)$pdo->lastInsertId();
|
||||
|
||||
// 写入联系方式
|
||||
// 写入联系方式(v1.0.16:支持 is_defult 字段,1常用/0备用)
|
||||
$contacts = json_decode($_POST['contacts'] ?? '[]', true);
|
||||
if (is_array($contacts)) {
|
||||
$ins = $pdo->prepare(
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, remark, is_primary)
|
||||
VALUES ('person', ?, ?, ?, ?, ?, ?)"
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, remark, is_primary, is_defult)
|
||||
VALUES ('person', ?, ?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
foreach ($contacts as $c) {
|
||||
$platform = trim($c['platform'] ?? '');
|
||||
$accountId = trim($c['account_id'] ?? '');
|
||||
if ($platform === '' || $accountId === '') continue;
|
||||
$ins->execute([$newId, $platform, $accountId, $c['profile_url'] ?? null, $c['remark'] ?? null, !empty($c['is_primary']) ? 1 : 0]);
|
||||
$ins->execute([$newId, $platform, $accountId, $c['profile_url'] ?? null, $c['remark'] ?? null, !empty($c['is_primary']) ? 1 : 0, !empty($c['is_defult']) ? 1 : 0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-2
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员详情接口 GET /api/person/detail.php?id=1
|
||||
* v1.0.16:联系方式改为“手机”“邮箱”两字段(仅常用);另有全部账号列表 accounts 供编辑回显
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
@@ -22,8 +23,24 @@ if (!$person) {
|
||||
Response::error('人员不存在');
|
||||
}
|
||||
|
||||
$accounts = $pdo->prepare("SELECT id, platform, account_id, profile_url, remark, is_primary, is_active FROM social_accounts WHERE owner_type = 'person' AND owner_id = ? ORDER BY is_primary DESC, id DESC");
|
||||
$accounts = $pdo->prepare("SELECT id, platform, account_id, profile_url, remark, is_primary, is_defult, is_active FROM social_accounts WHERE owner_type = 'person' AND owner_id = ? ORDER BY is_defult DESC, is_primary DESC, id DESC");
|
||||
$accounts->execute([$id]);
|
||||
$accountList = $accounts->fetchAll();
|
||||
|
||||
// 常用手机/邮箱(优先 is_defult=1,其次 is_primary=1)
|
||||
$phone = '';
|
||||
$email = '';
|
||||
foreach ($accountList as $a) {
|
||||
if ($phone === '' && $a['platform'] === 'phone') {
|
||||
$phone = $a['account_id'];
|
||||
}
|
||||
if ($email === '' && $a['platform'] === 'email') {
|
||||
$email = $a['account_id'];
|
||||
}
|
||||
if ($phone !== '' && $email !== '') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$experiences = $pdo->prepare(
|
||||
"SELECT pwe.id, pwe.company_id, c.display_name, c.industry, pwe.position, pwe.department,
|
||||
@@ -35,4 +52,10 @@ $experiences = $pdo->prepare(
|
||||
);
|
||||
$experiences->execute([$id]);
|
||||
|
||||
Response::success(['person' => $person, 'accounts' => $accounts->fetchAll(), 'experiences' => $experiences->fetchAll()]);
|
||||
Response::success([
|
||||
'person' => $person,
|
||||
'accounts' => $accountList,
|
||||
'phone' => $phone,
|
||||
'email' => $email,
|
||||
'experiences' => $experiences->fetchAll(),
|
||||
]);
|
||||
|
||||
@@ -33,9 +33,9 @@ $whereSql = implode(' AND ', $where);
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT p.id, p.union_id, p.full_name, p.gender, p.nationality, p.id_type, p.id_number,
|
||||
p.education, p.graduated_from, p.hometown, p.work_location, p.created_at,
|
||||
(SELECT sa.account_id FROM social_accounts sa WHERE sa.owner_type='person' AND sa.owner_id=p.id AND sa.platform='phone' AND sa.is_active=1 LIMIT 1) AS phone,
|
||||
(SELECT sa.account_id FROM social_accounts sa WHERE sa.owner_type='person' AND sa.owner_id=p.id AND sa.platform='email' AND sa.is_active=1 LIMIT 1) AS email
|
||||
p.education, p.graduated_from, p.hometown, p.work_location, p.source_channel, p.source_detail, p.created_at,
|
||||
(SELECT sa.account_id FROM social_accounts sa WHERE sa.owner_type='person' AND sa.owner_id=p.id AND sa.platform='phone' AND sa.is_active=1 ORDER BY sa.is_defult DESC, sa.is_primary DESC LIMIT 1) AS phone,
|
||||
(SELECT sa.account_id FROM social_accounts sa WHERE sa.owner_type='person' AND sa.owner_id=p.id AND sa.platform='email' AND sa.is_active=1 ORDER BY sa.is_defult DESC, sa.is_primary DESC LIMIT 1) AS email
|
||||
FROM persons p WHERE $whereSql ORDER BY p.id DESC"
|
||||
);
|
||||
$stmt->execute($params);
|
||||
@@ -47,12 +47,12 @@ header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename="persons_' . date('Ymd_His') . '.csv"');
|
||||
echo "\xEF\xBB\xBF";
|
||||
$out = fopen('php://output', 'w');
|
||||
fputcsv($out, ['ID', 'union_id', '姓名', '性别', '国籍', '证件类型', '证件号', '学历', '毕业院校', '家乡', '工作所在地', '手机', '邮箱', '创建时间']);
|
||||
fputcsv($out, ['ID', 'union_id', '姓名', '性别', '国籍', '证件类型', '证件号', '学历', '毕业院校', '家乡', '工作所在地', '来源渠道', '来源详情', '手机', '邮箱', '创建时间']);
|
||||
foreach ($list as $r) {
|
||||
fputcsv($out, [
|
||||
$r['id'], $r['union_id'], $r['full_name'], $r['gender'], $r['nationality'],
|
||||
$r['id_type'], $r['id_number'], $r['education'], $r['graduated_from'],
|
||||
$r['hometown'], $r['work_location'], $r['phone'], $r['email'], $r['created_at'],
|
||||
$r['hometown'], $r['work_location'], $r['source_channel'], $r['source_detail'], $r['phone'], $r['email'], $r['created_at'],
|
||||
]);
|
||||
}
|
||||
fclose($out);
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/**
|
||||
* 人员 CSV 导入接口 POST /api/person/import.php (multipart/form-data, 字段名 file)
|
||||
* CSV 表头:union_id,full_name,gender,nationality,id_type,id_number,education,
|
||||
* graduated_from,hometown,work_location,phone,email
|
||||
* 仅 full_name 必填;union_id 留空自动生成;phone/email 写入 social_accounts。
|
||||
* graduated_from,hometown,work_location,phone,email,source_channel,source_detail
|
||||
* 仅 full_name 必填;union_id 留空自动生成;phone/email 写入 social_accounts(默认常用)。
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
@@ -26,12 +26,12 @@ $header = str_getcsv(trim($first));
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
$insPerson = $pdo->prepare(
|
||||
"INSERT INTO persons (union_id, full_name, gender, nationality, id_type, id_number, education, graduated_from, hometown, work_location)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?)"
|
||||
"INSERT INTO persons (union_id, full_name, gender, nationality, id_type, id_number, education, graduated_from, hometown, work_location, source_channel, source_detail)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"
|
||||
);
|
||||
$insAccount = $pdo->prepare(
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, is_primary)
|
||||
VALUES ('person', ?, ?, ?, ?)"
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, is_defult)
|
||||
VALUES ('person', ?, ?, ?, 1)"
|
||||
);
|
||||
|
||||
$inserted = 0;
|
||||
@@ -63,13 +63,14 @@ while (($row = fgetcsv($handle)) !== false) {
|
||||
$unionId, $rec['full_name'], $rec['gender'] ?? '保密', $rec['nationality'] ?? null,
|
||||
$rec['id_type'] ?? null, $rec['id_number'] ?? null, $rec['education'] ?? null,
|
||||
$rec['graduated_from'] ?? null, $rec['hometown'] ?? null, $rec['work_location'] ?? null,
|
||||
$rec['source_channel'] ?? null, $rec['source_detail'] ?? null,
|
||||
]);
|
||||
$newId = (int)$pdo->lastInsertId();
|
||||
if (!empty($rec['phone'])) {
|
||||
$insAccount->execute([$newId, 'phone', $rec['phone'], 1]);
|
||||
$insAccount->execute([$newId, 'phone', $rec['phone']]);
|
||||
}
|
||||
if (!empty($rec['email'])) {
|
||||
$insAccount->execute([$newId, 'email', $rec['email'], 0]);
|
||||
$insAccount->execute([$newId, 'email', $rec['email']]);
|
||||
}
|
||||
$inserted++;
|
||||
} catch (Exception $e) {
|
||||
|
||||
+12
-2
@@ -3,6 +3,7 @@
|
||||
* 人员列表接口 GET/POST /api/person/list.php
|
||||
* 参数:page / limit / keyword(姓名/证件号/手机/邮箱)/ gender / nationality / work_location / is_active
|
||||
* 返回:{ list, total, page, limit }
|
||||
* v1.0.16:联系方式列改为“手机”“邮箱”两个字段(仅返回常用:is_defult=1 优先,其次 is_primary=1)
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
@@ -44,12 +45,21 @@ $stmt = $pdo->prepare("SELECT COUNT(*) FROM persons p WHERE $whereSql");
|
||||
$stmt->execute($params);
|
||||
$total = (int)$stmt->fetchColumn();
|
||||
|
||||
// 常用手机/邮箱:优先 is_defult=1,其次 is_primary=1,最后取任意一条
|
||||
$phoneSql = "(SELECT sa.account_id FROM social_accounts sa
|
||||
WHERE sa.owner_type = 'person' AND sa.owner_id = p.id AND sa.platform = 'phone' AND sa.is_active = 1
|
||||
ORDER BY sa.is_defult DESC, sa.is_primary DESC, sa.id DESC LIMIT 1)";
|
||||
$emailSql = "(SELECT sa.account_id FROM social_accounts sa
|
||||
WHERE sa.owner_type = 'person' AND sa.owner_id = p.id AND sa.platform = 'email' AND sa.is_active = 1
|
||||
ORDER BY sa.is_defult DESC, sa.is_primary DESC, sa.id DESC LIMIT 1)";
|
||||
|
||||
$offset = ($page - 1) * $limit;
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT p.id, p.union_id, p.full_name, p.gender, p.nationality, p.id_type, p.id_number,
|
||||
p.education, p.graduated_from, p.hometown, p.work_location, p.is_active, p.created_at,
|
||||
(SELECT GROUP_CONCAT(CONCAT(sa.platform, ':', sa.account_id) SEPARATOR ' | ')
|
||||
FROM social_accounts sa WHERE sa.owner_type = 'person' AND sa.owner_id = p.id AND sa.is_active = 1) AS contacts
|
||||
p.source_channel, p.source_detail,
|
||||
$phoneSql AS phone,
|
||||
$emailSql AS email
|
||||
FROM persons p
|
||||
WHERE $whereSql
|
||||
ORDER BY p.id DESC
|
||||
|
||||
@@ -36,14 +36,14 @@ if (isset($_POST['contacts'])) {
|
||||
$contacts = json_decode($_POST['contacts'], true);
|
||||
if (is_array($contacts)) {
|
||||
$ins = $pdo->prepare(
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, remark, is_primary)
|
||||
VALUES ('person', ?, ?, ?, ?, ?, ?)"
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, remark, is_primary, is_defult)
|
||||
VALUES ('person', ?, ?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
foreach ($contacts as $c) {
|
||||
$platform = trim($c['platform'] ?? '');
|
||||
$accountId = trim($c['account_id'] ?? '');
|
||||
if ($platform === '' || $accountId === '') continue;
|
||||
$ins->execute([$id, $platform, $accountId, $c['profile_url'] ?? null, $c['remark'] ?? null, !empty($c['is_primary']) ? 1 : 0]);
|
||||
$ins->execute([$id, $platform, $accountId, $c['profile_url'] ?? null, $c['remark'] ?? null, !empty($c['is_primary']) ? 1 : 0, !empty($c['is_defult']) ? 1 : 0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user