新增功能

This commit is contained in:
Your Name
2026-08-07 14:32:35 +08:00
parent 16d301f302
commit 58a7197d3e
383 changed files with 713 additions and 542 deletions
@@ -81,7 +81,7 @@ class FirstVisitConversionLogic
'start_date' => $startDate,
'end_date' => $endDate,
'include_filters' => 1,
'include_members' => 0,
'include_members' => 1,
'exclude_cancelled_appointments' => 1,
'order_metric_mode' => 'performance',
'page_no' => 1,
@@ -109,14 +109,15 @@ class FirstVisitConversionLogic
$rowDeptIdSet = [];
self::collectRowDeptIds($rows, $rowDeptIdSet);
$openDirect = self::loadOpenCountByDept(
$openCounts = self::loadOpenCounts(
$startDate,
$endDate,
$effectiveAdminIds,
array_fill_keys(array_keys($rowDeptIdSet), true),
self::personalYejiMediaSources($selectedMediaChannelCode, $selectedMediaChannel)
);
self::applyOpenCounts($rows, $openDirect);
$openDirect = $openCounts['dept'];
self::applyOpenCounts($rows, $openDirect, $openCounts['admin']);
$summary = is_array($conversion['summary'] ?? null) ? $conversion['summary'] : [];
$summary['total_open_count'] = array_sum($openDirect);
@@ -170,6 +171,7 @@ class FirstVisitConversionLogic
? '个人业绩录入'
: '个人业绩录入(按渠道名称匹配)',
'appointment_rule' => '按预约日期统计,归属优先挂号医助、再回退诊单医助;仅含已预约、已完成和已过号',
'registration_rule' => '按支付时间统计已支付且实收金额大于 0、低于 10 元的订单,每笔计 1 个挂号并按订单创建人归属',
'performance_rule' => '按业务订单创建时间和创建人统计,排除取消、拒收、退款及已发生退款的订单',
],
'filters' => [
@@ -294,6 +296,10 @@ class FirstVisitConversionLogic
if (!is_array($row)) {
continue;
}
if (in_array((string) ($row['type'] ?? ''), ['member', 'unbound'], true)) {
$out[] = $row;
continue;
}
$children = self::filterDeptRows(is_array($row['children'] ?? null) ? $row['children'] : [], $allowedSet);
$id = (int) ($row['id'] ?? 0);
if (isset($allowedSet[$id])) {
@@ -328,9 +334,9 @@ class FirstVisitConversionLogic
* @param int[]|null $effectiveAdminIds
* @param array<int,true> $rowDeptSet
* @param string[]|null $mediaSources null=全部渠道;空数组=所选渠道没有可匹配的手工来源
* @return array<int,int>
* @return array{dept:array<int,int>,admin:array<int,int>}
*/
private static function loadOpenCountByDept(
private static function loadOpenCounts(
string $startDate,
string $endDate,
?array $effectiveAdminIds,
@@ -339,7 +345,7 @@ class FirstVisitConversionLogic
): array
{
if ($effectiveAdminIds === [] || $rowDeptSet === [] || $mediaSources === []) {
return [];
return ['dept' => [], 'admin' => []];
}
$query = PersonalYeji::whereBetween('yeji_date', [$startDate, $endDate]);
if ($effectiveAdminIds !== null) {
@@ -354,7 +360,7 @@ class FirstVisitConversionLogic
->select()
->toArray();
if ($rows === []) {
return [];
return ['dept' => [], 'admin' => []];
}
$creatorIds = self::normalizeIds(array_column($rows, 'creator_id'));
@@ -415,6 +421,7 @@ class FirstVisitConversionLogic
unset($deptIds);
$direct = [];
$adminDirect = [];
foreach ($rows as $row) {
$adminId = (int) ($row['creator_id'] ?? 0);
$targetDeptId = 0;
@@ -428,24 +435,48 @@ class FirstVisitConversionLogic
$targetDeptId = -2;
}
if ($targetDeptId !== 0) {
$direct[$targetDeptId] = ($direct[$targetDeptId] ?? 0) + (int) ($row['open_count'] ?? 0);
$openCount = (int) ($row['open_count'] ?? 0);
$direct[$targetDeptId] = ($direct[$targetDeptId] ?? 0) + $openCount;
$adminDirect[$adminId] = ($adminDirect[$adminId] ?? 0) + $openCount;
}
}
return $direct;
return ['dept' => $direct, 'admin' => $adminDirect];
}
/** @param array<int,array<string,mixed>> $rows @param array<int,int> $direct */
private static function applyOpenCounts(array &$rows, array $direct): int
/**
* @param array<int,array<string,mixed>> $rows
* @param array<int,int> $deptDirect
* @param array<int,int> $adminDirect
*/
private static function applyOpenCounts(array &$rows, array $deptDirect, array $adminDirect): int
{
$sum = 0;
foreach ($rows as &$row) {
$rowType = (string) ($row['type'] ?? '');
if (in_array($rowType, ['member', 'unbound'], true)) {
$count = $rowType === 'member'
? (int) ($adminDirect[(int) ($row['admin_id'] ?? 0)] ?? 0)
: 0;
$row['total_open_count'] = $count;
$row['total_open_rate'] = self::percent($count, (int) ($row['add_fans_count'] ?? 0));
$row['open_appointment_rate'] = self::percent(
(int) ($row['paid_appointment_count'] ?? 0),
$count
);
$row['open_receive_rate'] = self::percent(
(int) ($row['completed_order_count'] ?? 0),
$count
);
continue;
}
$children = is_array($row['children'] ?? null) ? $row['children'] : [];
$childTotal = self::applyOpenCounts($children, $direct);
$childTotal = self::applyOpenCounts($children, $deptDirect, $adminDirect);
if ($children !== []) {
$row['children'] = $children;
}
$count = (int) ($direct[(int) ($row['id'] ?? 0)] ?? 0) + $childTotal;
$directCount = (int) ($deptDirect[(int) ($row['id'] ?? 0)] ?? 0);
$count = $directCount + $childTotal;
$row['total_open_count'] = $count;
$row['total_open_rate'] = self::percent($count, (int) ($row['add_fans_count'] ?? 0));
$row['open_appointment_rate'] = self::percent(
@@ -453,7 +484,7 @@ class FirstVisitConversionLogic
$count
);
$row['open_receive_rate'] = self::percent((int) ($row['completed_order_count'] ?? 0), $count);
$sum += (int) ($direct[(int) ($row['id'] ?? 0)] ?? 0) + $childTotal;
$sum += $directCount + $childTotal;
}
unset($row);