This commit is contained in:
Your Name
2026-08-05 11:08:02 +08:00
parent 57a7c415a1
commit c2b7018a22
429 changed files with 13316 additions and 350 deletions
@@ -22,6 +22,8 @@ class ConversionLogic
* @param array $params
* @param int $adminId 当前操作 admin(来自 BaseAdminController
* @param array $adminInfo 当前 admin 完整信息(含 root / role_id 数组等)
* @param int[]|null $trustedVisibleAdminIdsOverride 仅供服务端内部可信调用覆盖本次可见管理员;不从 HTTP 参数读取
* @param int[]|null $trustedCostAllocationAdminIdsOverride 仅用于成本按加粉占比分摊的分母,不会放大任何业务指标
* @return array<string, mixed>
*
* 数据权限:通过 DataScopeService::getVisibleAdminIds 拿到当前用户的"可见 admin id 集合"。
@@ -29,7 +31,13 @@ class ConversionLogic
* - []:可见为空(SCOPE_SELF 且无绑定且关闭 fallback),返回空数据
* - 其他:用 visibleAdminIds 收窄 entities 加载、hydrate 数据归属、虚拟桶可见性、filters 选项
*/
public static function overview(array $params = [], int $adminId = 0, ?array $adminInfo = null): array
public static function overview(
array $params = [],
int $adminId = 0,
?array $adminInfo = null,
?array $trustedVisibleAdminIdsOverride = null,
?array $trustedCostAllocationAdminIdsOverride = null
): array
{
$includeFilters = (int)($params['include_filters'] ?? 0) === 1;
$dimension = self::normalizeDimension((string)($params['dimension'] ?? 'dept'));
@@ -38,11 +46,29 @@ class ConversionLogic
$filterEmptyEntities = $mediaChannel !== null;
[$startTimestamp, $endTimestamp, $startDate, $endDate] = self::resolveTimeRange($params);
$pageNo = max(1, (int)($params['page_no'] ?? 1));
$pageSize = max(1, min(100, (int)($params['page_size'] ?? 15)));
if ($trustedVisibleAdminIdsOverride !== null) {
$trustedVisibleAdminIdsOverride = array_values(array_unique(array_filter(
array_map('intval', $trustedVisibleAdminIdsOverride),
static fn (int $id): bool => $id > 0
)));
}
if ($trustedCostAllocationAdminIdsOverride !== null) {
$trustedCostAllocationAdminIdsOverride = array_values(array_unique(array_filter(
array_map('intval', $trustedCostAllocationAdminIdsOverride),
static fn (int $id): bool => $id > 0
)));
}
$pageSizeLimit = $trustedVisibleAdminIdsOverride !== null
? max(100, count($trustedVisibleAdminIdsOverride))
: 100;
$pageSize = max(1, min($pageSizeLimit, (int)($params['page_size'] ?? 15)));
$visibleAdminIds = ($adminInfo !== null && $adminId > 0)
? DataScopeService::getVisibleAdminIds($adminId, $adminInfo)
: null;
$visibleAdminIds = $trustedVisibleAdminIdsOverride;
if ($trustedVisibleAdminIdsOverride === null) {
$visibleAdminIds = ($adminInfo !== null && $adminId > 0)
? DataScopeService::getVisibleAdminIds($adminId, $adminInfo)
: null;
}
// 严格隔离:可见 admin 集合为空时直接返回空骨架,避免下游误以为是"全部"。
if ($visibleAdminIds === []) {
$emptyResult = [
@@ -98,7 +124,23 @@ class ConversionLogic
$adminToDeptIds = self::loadAdminDeptMap();
self::hydrateFanStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds);
$allocationEntities = $entities;
$allocationEntityIds = $entityIds;
if ($trustedCostAllocationAdminIdsOverride !== null) {
// 个人口径下,仍以同部门全员加粉作为成本分摊分母,避免将整个部门成本全部计到一个人。
$allocationEntities = self::loadEntities($dimension, $params, $trustedCostAllocationAdminIdsOverride);
// 分摊只能使用实际响应中已允许的部门,防止同事的多部门绑定扩大成本范围。
$allocationEntities = array_intersect_key($allocationEntities, $entities);
$allocationEntityIds = array_keys($allocationEntities);
self::hydrateFanStats(
$allocationEntities,
$dimension,
$allocationEntityIds,
$adminToDeptIds,
$startTimestamp,
$endTimestamp,
$mediaChannel,
$trustedCostAllocationAdminIdsOverride
);
}
self::hydrateAppointmentStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $startDate, $endDate, $mediaChannel, $visibleAdminIds);
self::hydrateOrderAndAmountStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds);
// 数据隔离:可见部门 = 可见 admin 所属部门并集;用于 account_cost 与下游 cost 分摊。