v1.0.19: 修复人员编辑入口缺失(person.js addPerson/editPerson) + 渠道明细数量字段名(analysis.php cnt) + CDP全量验证43项PASS

This commit is contained in:
nanguaboss
2026-08-08 19:29:14 +08:00
parent 2cb688ed46
commit 1c8b374a72
40 changed files with 2313 additions and 658 deletions
+85
View File
@@ -0,0 +1,85 @@
<?php
/**
* 渠道效能分析接口 GET /api/channel/analysis.php?year=2025
* v1.0.18 渠道管理 - 渠道效能分析:
* - 企业/人员两个维度,分别按 source_channel(渠道字段)分组计数、按数量降序、计算百分比
* - 每个渠道附带 source_detail TOP10 排名(来源/数量)
* - year 为空 = 全部年份;否则按创建年份过滤
* 返回:{ years, company: [{channel, count, percent, details:[{source,count}]}], person: [...] }
*/
require_once __DIR__ . '/../common/db.php';
require_once __DIR__ . '/../common/response.php';
require_once __DIR__ . '/../common/auth.php';
checkPermission('channel');
$year = trim($_REQUEST['year'] ?? '');
if ($year !== '' && (!ctype_digit($year) || (int)$year < 2000 || (int)$year > 2100)) {
$year = '';
}
$pdo = DB::getInstance()->getPdo();
// 可选年份(企业/人员创建年份并集)
$years = $pdo->query(
"SELECT DISTINCT y FROM (
SELECT YEAR(created_at) AS y FROM companies WHERE is_active = 1 AND created_at IS NOT NULL
UNION
SELECT YEAR(created_at) AS y FROM persons WHERE is_active = 1 AND created_at IS NOT NULL
) t ORDER BY y DESC"
)->fetchAll(PDO::FETCH_COLUMN);
/** 单维度渠道分析 */
function channelAnalysis($pdo, $table, $year)
{
$where = 'is_active = 1 AND source_channel IS NOT NULL AND source_channel <> \'\'';
$params = [];
if ($year !== '') {
$where .= ' AND YEAR(created_at) = ?';
$params[] = (int)$year;
}
$stmt = $pdo->prepare(
"SELECT source_channel AS channel, COUNT(*) AS cnt
FROM $table WHERE $where
GROUP BY source_channel ORDER BY cnt DESC"
);
$stmt->execute($params);
$rows = $stmt->fetchAll();
$total = 0;
foreach ($rows as $r) {
$total += (int)$r['cnt'];
}
$result = [];
foreach ($rows as $r) {
$channel = $r['channel'];
// 该渠道 source_detail TOP10
$detailStmt = $pdo->prepare(
"SELECT COALESCE(NULLIF(TRIM(source_detail), ''), '(未填写)') AS source, COUNT(*) AS cnt
FROM $table
WHERE is_active = 1 AND source_channel = ?" . ($year !== '' ? ' AND YEAR(created_at) = ?' : '') . "
GROUP BY source ORDER BY cnt DESC LIMIT 10"
);
$dParams = [$channel];
if ($year !== '') {
$dParams[] = (int)$year;
}
$detailStmt->execute($dParams);
$result[] = [
'channel' => $channel,
'count' => (int)$r['cnt'],
'percent' => $total > 0 ? round(((int)$r['cnt'] / $total) * 100, 1) : 0,
'details' => $detailStmt->fetchAll(),
];
}
return $result;
}
Response::success([
'years' => $years,
'company' => channelAnalysis($pdo, 'companies', $year),
'person' => channelAnalysis($pdo, 'persons', $year),
]);