v1.0.10
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员新增接口 POST /api/person/add.php
|
||||
* 必填:full_name;union_id 为空时自动生成。
|
||||
* 可选:contacts(JSON 数组,如 [{"platform":"email","account_id":"a@b.com","is_primary":1}])
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
require_once __DIR__ . '/../common/logger.php';
|
||||
require_once __DIR__ . '/../common/helpers.php';
|
||||
|
||||
checkAjax();
|
||||
checkPermission('person');
|
||||
|
||||
$data = extractFields(PERSON_FIELDS);
|
||||
if (empty($data['full_name'])) {
|
||||
Response::error('姓名(full_name)为必填项', 400);
|
||||
}
|
||||
if (empty($data['union_id'])) {
|
||||
$data['union_id'] = 'P' . date('YmdHis') . substr(uniqid(), -6);
|
||||
}
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
|
||||
// union_id 唯一性
|
||||
$chk = $pdo->prepare("SELECT COUNT(*) FROM persons WHERE union_id = ?");
|
||||
$chk->execute([$data['union_id']]);
|
||||
if ((int)$chk->fetchColumn() > 0) {
|
||||
Response::error('union_id 已存在,请更换');
|
||||
}
|
||||
|
||||
[$sql, $params] = buildInsert($data);
|
||||
$pdo->prepare("INSERT INTO persons $sql")->execute($params);
|
||||
$newId = (int)$pdo->lastInsertId();
|
||||
|
||||
// 写入联系方式
|
||||
$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', ?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
logCurrent('add', 'person', 'persons', $newId, ['data' => $data, 'contacts' => $contacts]);
|
||||
Response::success(['id' => $newId], '新增成功');
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员任职公司列表接口 GET /api/person/companies.php
|
||||
* 入参:person_id(必填)/ page / limit
|
||||
* 返回:该人员任职的公司列表(公司名称/部门/岗位/职级/入职日期/是否在岗)
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
|
||||
checkPermission('person');
|
||||
|
||||
$personId = (int)($_REQUEST['person_id'] ?? 0);
|
||||
if ($personId <= 0) {
|
||||
Response::error('参数错误', 400);
|
||||
}
|
||||
|
||||
[$page, $limit] = pageParams(5);
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
|
||||
$chk = $pdo->prepare("SELECT COUNT(*) FROM persons WHERE id = ?");
|
||||
$chk->execute([$personId]);
|
||||
if ((int)$chk->fetchColumn() === 0) {
|
||||
Response::error('人员不存在');
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT COUNT(*) FROM person_work_experiences pwe
|
||||
INNER JOIN companies c ON c.id = pwe.company_id
|
||||
WHERE pwe.person_id = ? AND pwe.is_active = 1"
|
||||
);
|
||||
$stmt->execute([$personId]);
|
||||
$total = (int)$stmt->fetchColumn();
|
||||
|
||||
$offset = ($page - 1) * $limit;
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT pwe.id AS work_id, pwe.company_id,
|
||||
CASE WHEN c.name_zh IS NOT NULL AND c.name_zh <> '' THEN c.name_zh
|
||||
ELSE COALESCE(c.name_en, c.display_name) END AS company_name,
|
||||
c.industry, pwe.department, pwe.position, pwe.job_level,
|
||||
pwe.start_date, pwe.end_date, pwe.is_current
|
||||
FROM person_work_experiences pwe
|
||||
INNER JOIN companies c ON c.id = pwe.company_id
|
||||
WHERE pwe.person_id = ? AND pwe.is_active = 1
|
||||
ORDER BY pwe.is_current DESC, pwe.start_date DESC
|
||||
LIMIT $limit OFFSET $offset"
|
||||
);
|
||||
$stmt->execute([$personId]);
|
||||
$list = $stmt->fetchAll();
|
||||
|
||||
Response::success(['list' => $list, 'total' => $total, 'page' => $page, 'limit' => $limit]);
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员删除接口(软删除) POST /api/person/delete.php
|
||||
* 入参:id(或 ids 逗号分隔批量)
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
require_once __DIR__ . '/../common/logger.php';
|
||||
|
||||
checkAjax();
|
||||
checkPermission('person');
|
||||
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
$ids = trim($_POST['ids'] ?? '');
|
||||
$idList = [];
|
||||
if ($id > 0) $idList[] = $id;
|
||||
if ($ids !== '') {
|
||||
foreach (explode(',', $ids) as $v) {
|
||||
$v = (int)trim($v);
|
||||
if ($v > 0) $idList[] = $v;
|
||||
}
|
||||
}
|
||||
$idList = array_unique($idList);
|
||||
if (!$idList) {
|
||||
Response::error('参数错误', 400);
|
||||
}
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
$in = implode(',', array_fill(0, count($idList), '?'));
|
||||
$stmt = $pdo->prepare("UPDATE persons SET is_active = 0 WHERE id IN ($in)");
|
||||
$stmt->execute($idList);
|
||||
$affected = $stmt->rowCount();
|
||||
|
||||
logCurrent('delete', 'person', 'persons', null, ['ids' => $idList]);
|
||||
Response::success(['affected' => $affected], "已删除 $affected 条记录");
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员详情接口 GET /api/person/detail.php?id=1
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
|
||||
checkPermission('person');
|
||||
|
||||
$id = (int)($_REQUEST['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
Response::error('参数错误', 400);
|
||||
}
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM persons WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$person = $stmt->fetch();
|
||||
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->execute([$id]);
|
||||
|
||||
$experiences = $pdo->prepare(
|
||||
"SELECT pwe.id, pwe.company_id, c.display_name, c.industry, pwe.position, pwe.department,
|
||||
pwe.job_level, pwe.start_date, pwe.end_date, pwe.is_current
|
||||
FROM person_work_experiences pwe
|
||||
LEFT JOIN companies c ON c.id = pwe.company_id
|
||||
WHERE pwe.person_id = ? AND pwe.is_active = 1
|
||||
ORDER BY pwe.is_current DESC, pwe.start_date DESC"
|
||||
);
|
||||
$experiences->execute([$id]);
|
||||
|
||||
Response::success(['person' => $person, 'accounts' => $accounts->fetchAll(), 'experiences' => $experiences->fetchAll()]);
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员导出接口(CSV) GET/POST /api/person/export.php
|
||||
* 参数同 list.php
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
require_once __DIR__ . '/../common/logger.php';
|
||||
|
||||
checkPermission('person');
|
||||
|
||||
// 仅导出勾选的人员
|
||||
$idsRaw = trim($_REQUEST['ids'] ?? '');
|
||||
$idList = [];
|
||||
if ($idsRaw !== '') {
|
||||
foreach (explode(',', $idsRaw) as $v) {
|
||||
$v = (int)trim($v);
|
||||
if ($v > 0) {
|
||||
$idList[] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
$idList = array_unique($idList);
|
||||
if (!$idList) {
|
||||
Response::error('请先选择需要导出的人员数据', 1);
|
||||
}
|
||||
|
||||
$where = ['p.id IN (' . implode(',', array_fill(0, count($idList), '?')) . ')', 'p.is_active = 1'];
|
||||
$params = $idList;
|
||||
$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
|
||||
FROM persons p WHERE $whereSql ORDER BY p.id DESC"
|
||||
);
|
||||
$stmt->execute($params);
|
||||
$list = $stmt->fetchAll();
|
||||
|
||||
logCurrent('export', 'person', 'persons', null, ['count' => count($list)]);
|
||||
|
||||
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', '姓名', '性别', '国籍', '证件类型', '证件号', '学历', '毕业院校', '家乡', '工作所在地', '手机', '邮箱', '创建时间']);
|
||||
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'],
|
||||
]);
|
||||
}
|
||||
fclose($out);
|
||||
exit;
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员 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。
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
require_once __DIR__ . '/../common/logger.php';
|
||||
|
||||
checkAjax();
|
||||
checkPermission('person');
|
||||
|
||||
if (empty($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
|
||||
Response::error('请选择要上传的CSV文件', 400);
|
||||
}
|
||||
|
||||
$handle = fopen($_FILES['file']['tmp_name'], 'r');
|
||||
if (!$handle) {
|
||||
Response::error('无法读取文件', 400);
|
||||
}
|
||||
$first = preg_replace('/^\xEF\xBB\xBF/', '', fgets($handle));
|
||||
$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 (?,?,?,?,?,?,?,?,?,?)"
|
||||
);
|
||||
$insAccount = $pdo->prepare(
|
||||
"INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, is_primary)
|
||||
VALUES ('person', ?, ?, ?, ?)"
|
||||
);
|
||||
|
||||
$inserted = 0;
|
||||
$failed = 0;
|
||||
|
||||
while (($row = fgetcsv($handle)) !== false) {
|
||||
$row = array_map('trim', $row);
|
||||
$rec = [];
|
||||
foreach ($header as $idx => $col) {
|
||||
$col = trim($col);
|
||||
if (isset($row[$idx])) {
|
||||
$rec[$col] = $row[$idx];
|
||||
}
|
||||
}
|
||||
if (empty($rec['full_name'])) {
|
||||
$failed++;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$unionId = !empty($rec['union_id']) ? $rec['union_id'] : ('P' . date('YmdHis') . substr(uniqid(), -6));
|
||||
// 跳过重复 union_id
|
||||
$chk = $pdo->prepare("SELECT COUNT(*) FROM persons WHERE union_id = ?");
|
||||
$chk->execute([$unionId]);
|
||||
if ((int)$chk->fetchColumn() > 0) {
|
||||
$failed++;
|
||||
continue;
|
||||
}
|
||||
$insPerson->execute([
|
||||
$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,
|
||||
]);
|
||||
$newId = (int)$pdo->lastInsertId();
|
||||
if (!empty($rec['phone'])) {
|
||||
$insAccount->execute([$newId, 'phone', $rec['phone'], 1]);
|
||||
}
|
||||
if (!empty($rec['email'])) {
|
||||
$insAccount->execute([$newId, 'email', $rec['email'], 0]);
|
||||
}
|
||||
$inserted++;
|
||||
} catch (Exception $e) {
|
||||
$failed++;
|
||||
}
|
||||
}
|
||||
fclose($handle);
|
||||
|
||||
logCurrent('import', 'person', 'persons', null, ['inserted' => $inserted, 'failed' => $failed]);
|
||||
Response::success(['inserted' => $inserted, 'failed' => $failed], "导入完成:成功 $inserted 条,失败 $failed 条");
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员列表接口 GET/POST /api/person/list.php
|
||||
* 参数:page / limit / keyword(姓名/证件号/手机/邮箱)/ gender / nationality / work_location / is_active
|
||||
* 返回:{ list, total, page, limit }
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
|
||||
checkPermission('person');
|
||||
|
||||
[$page, $limit] = pageParams();
|
||||
$keyword = trim($_REQUEST['keyword'] ?? '');
|
||||
$gender = trim($_REQUEST['gender'] ?? '');
|
||||
$nationality = trim($_REQUEST['nationality'] ?? '');
|
||||
$location = trim($_REQUEST['work_location'] ?? '');
|
||||
$active = isset($_REQUEST['is_active']) && $_REQUEST['is_active'] !== '' ? (int)$_REQUEST['is_active'] : null;
|
||||
|
||||
$where = ['p.is_active = 1'];
|
||||
$params = [];
|
||||
if ($active !== null) {
|
||||
$where = ['p.is_active = ?'];
|
||||
$params = [$active];
|
||||
}
|
||||
if ($keyword !== '') {
|
||||
// 姓名/证件号直查;手机/邮箱通过 social_accounts 关联
|
||||
$where[] = "(p.full_name LIKE ? OR p.id_number LIKE ? OR p.union_id LIKE ? OR EXISTS (
|
||||
SELECT 1 FROM social_accounts sa
|
||||
WHERE sa.owner_type = 'person' AND sa.owner_id = p.id AND sa.is_active = 1
|
||||
AND sa.account_id LIKE ?
|
||||
))";
|
||||
$like = "%$keyword%";
|
||||
array_push($params, $like, $like, $like, $like);
|
||||
}
|
||||
if ($gender !== '') { $where[] = 'p.gender = ?'; $params[] = $gender; }
|
||||
if ($nationality !== '') { $where[] = 'p.nationality = ?'; $params[] = $nationality; }
|
||||
if ($location !== '') { $where[] = 'p.work_location LIKE ?'; $params[] = "%$location%"; }
|
||||
$whereSql = implode(' AND ', $where);
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM persons p WHERE $whereSql");
|
||||
$stmt->execute($params);
|
||||
$total = (int)$stmt->fetchColumn();
|
||||
|
||||
$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
|
||||
FROM persons p
|
||||
WHERE $whereSql
|
||||
ORDER BY p.id DESC
|
||||
LIMIT $limit OFFSET $offset"
|
||||
);
|
||||
$stmt->execute($params);
|
||||
$list = $stmt->fetchAll();
|
||||
|
||||
Response::success(['list' => $list, 'total' => $total, 'page' => $page, 'limit' => $limit]);
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* 人员编辑接口 POST /api/person/update.php
|
||||
* 入参:id + 白名单字段;可选 contacts(JSON 数组,整体替换联系方式)
|
||||
*/
|
||||
require_once __DIR__ . '/../common/db.php';
|
||||
require_once __DIR__ . '/../common/response.php';
|
||||
require_once __DIR__ . '/../common/auth.php';
|
||||
require_once __DIR__ . '/../common/logger.php';
|
||||
require_once __DIR__ . '/../common/helpers.php';
|
||||
|
||||
checkAjax();
|
||||
checkPermission('person');
|
||||
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
Response::error('参数错误', 400);
|
||||
}
|
||||
|
||||
$data = extractFields(PERSON_FIELDS);
|
||||
unset($data['union_id']); // 不允许修改 union_id
|
||||
|
||||
$pdo = DB::getInstance()->getPdo();
|
||||
$check = $pdo->prepare("SELECT * FROM persons WHERE id = ?");
|
||||
$check->execute([$id]);
|
||||
$old = $check->fetch();
|
||||
if (!$old) {
|
||||
Response::error('人员不存在');
|
||||
}
|
||||
|
||||
$contactsChanged = false;
|
||||
if (isset($_POST['contacts'])) {
|
||||
$contactsChanged = true;
|
||||
// 整体替换联系方式:先删旧(保留非联系人性质?此处直接删除全部后重建)
|
||||
$pdo->prepare("DELETE FROM social_accounts WHERE owner_type = 'person' AND owner_id = ?")->execute([$id]);
|
||||
$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', ?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
[$sets, $params] = buildUpdate($data);
|
||||
$params[] = $id;
|
||||
$pdo->prepare("UPDATE persons SET $sets WHERE id = ?")->execute($params);
|
||||
}
|
||||
|
||||
logCurrent('update', 'person', 'persons', $id, ['before' => $old, 'after' => $data, 'contacts_replaced' => $contactsChanged]);
|
||||
Response::success(null, '更新成功');
|
||||
Reference in New Issue
Block a user