更新
This commit is contained in:
@@ -126,7 +126,11 @@ class DeptController extends BaseAdminController
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
$result = DeptLogic::getAllData();
|
||||
$apply = (int) ($this->request->get('apply_data_scope', 0));
|
||||
$result = $apply === 1
|
||||
? DeptLogic::getAllDataScoped($this->adminId, $this->adminInfo)
|
||||
: DeptLogic::getAllData();
|
||||
|
||||
return $this->data($result);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use app\adminapi\logic\stats\YejiStatsLogic;
|
||||
* - GET stats.yeji-stats/multi 多区间一次返回(默认 月/周/今日/昨日 四张表)
|
||||
* - GET stats.yeji-stats/dept-options 部门下拉
|
||||
* - GET stats.yeji-stats/leaderboard 医助排行榜(按展示部门分表)
|
||||
* - GET stats.yeji-stats/unassignedBreakdown 「未归属中心」合计业绩按订单创建人拆解
|
||||
*/
|
||||
class YejiStatsController extends BaseAdminController
|
||||
{
|
||||
@@ -102,4 +103,13 @@ class YejiStatsController extends BaseAdminController
|
||||
|
||||
return $this->data(YejiStatsLogic::assistantLeaderboards($params, $this->adminId, $this->adminInfo));
|
||||
}
|
||||
|
||||
/** 「未归属中心」行:按订单创建人拆解业绩(与「合计业绩」未归属部分同口径) */
|
||||
public function unassignedBreakdown()
|
||||
{
|
||||
@set_time_limit(120);
|
||||
$params = $this->request->get();
|
||||
|
||||
return $this->data(YejiStatsLogic::unassignedCenterBreakdown($params, $this->adminId, $this->adminInfo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use app\common\logic\BaseLogic;
|
||||
use app\common\model\auth\Admin;
|
||||
use app\common\model\auth\AdminDept;
|
||||
use app\common\model\dept\Dept;
|
||||
use app\common\service\DataScope\DataScopeService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -284,6 +285,60 @@ class DeptLogic extends BaseLogic
|
||||
return self::getTree($data, $pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门树(与 getAllData 同结构),按当前管理员角色数据权限收窄可选节点;
|
||||
* 保留必选祖先节点以便树形展示(与业绩看板 deptOptions 的 allowed 集合一致)。
|
||||
*
|
||||
* @param array<string, mixed> $adminInfo BaseAdminController::$adminInfo 形态(须含 root、role_id 等)
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public static function getAllDataScoped(int $adminId, array $adminInfo): array
|
||||
{
|
||||
$full = self::getAllData();
|
||||
if ($full === []) {
|
||||
return [];
|
||||
}
|
||||
if ($adminId <= 0 || !DataScopeService::isEnabled()) {
|
||||
return $full;
|
||||
}
|
||||
$allowed = DataScopeService::getAllowedDeptIdSet($adminId, $adminInfo);
|
||||
if ($allowed === null) {
|
||||
return $full;
|
||||
}
|
||||
if ($allowed === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return self::filterDeptTreeByAllowedIds($full, $allowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $nodes
|
||||
* @param array<int, true> $allowedIdMap
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
private static function filterDeptTreeByAllowedIds(array $nodes, array $allowedIdMap): array
|
||||
{
|
||||
$out = [];
|
||||
foreach ($nodes as $node) {
|
||||
$id = (int) ($node['id'] ?? 0);
|
||||
$rawChildren = $node['children'] ?? [];
|
||||
$children = \is_array($rawChildren) && $rawChildren !== []
|
||||
? self::filterDeptTreeByAllowedIds($rawChildren, $allowedIdMap)
|
||||
: [];
|
||||
$inAllowed = isset($allowedIdMap[$id]);
|
||||
if ($inAllowed || $children !== []) {
|
||||
$row = $node;
|
||||
$row['children'] = $children;
|
||||
$out[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定部门及其全部下级部门 id(含自身)。筛选时选父级可匹配子级下成员(admin_dept.dept_id)。
|
||||
*
|
||||
|
||||
@@ -2499,6 +2499,158 @@ class YejiStatsLogic
|
||||
return self::$tagScopeCache[$tagFilterId] = [array_keys($diagIds), $assistantIds];
|
||||
}
|
||||
|
||||
/**
|
||||
* 「未归属中心」合计业绩按订单创建人拆解(与 aggregatePerformance /「合计业绩」列归属一致:仅 null,null 标签口径,不按渠道收窄)。
|
||||
*
|
||||
* @return array{
|
||||
* start_date: string,
|
||||
* end_date: string,
|
||||
* channel_code: string,
|
||||
* rows: list<array{admin_id:int, name:string, order_count:int, amount:float}>,
|
||||
* note: string
|
||||
* }
|
||||
*/
|
||||
public static function unassignedCenterBreakdown(array $params, int $viewerAdminId = 0, array $viewerAdminInfo = []): array
|
||||
{
|
||||
$c = self::resolveYejiContext($params);
|
||||
if ($viewerAdminId > 0) {
|
||||
self::applyYejiDataScope($c, $viewerAdminId, $viewerAdminInfo);
|
||||
}
|
||||
$startTs = (int) $c['startTs'];
|
||||
$endTs = (int) $c['endTs'];
|
||||
$adminToPrimary = $c['adminToPrimary'];
|
||||
$visibleCreatorIds = null;
|
||||
if (!empty($c['dataScopeRestricted'])) {
|
||||
$visibleCreatorIds = $c['dataScopeVisibleAdminIds'] ?? [];
|
||||
}
|
||||
$rows = self::aggregateUnassignedByCreator(
|
||||
$startTs,
|
||||
$endTs,
|
||||
$adminToPrimary,
|
||||
null,
|
||||
null,
|
||||
$visibleCreatorIds
|
||||
);
|
||||
$ids = [];
|
||||
foreach ($rows as $row) {
|
||||
if ($row['admin_id'] > 0) {
|
||||
$ids[] = $row['admin_id'];
|
||||
}
|
||||
}
|
||||
$names = self::batchAdminNames(array_values(array_unique($ids)));
|
||||
foreach ($rows as &$row) {
|
||||
$aid = (int) $row['admin_id'];
|
||||
if ($aid <= 0) {
|
||||
$row['name'] = '(无创建人/0)';
|
||||
} else {
|
||||
$row['name'] = (string) ($names[$aid] ?? ('#' . $aid));
|
||||
}
|
||||
}
|
||||
unset($row);
|
||||
|
||||
return [
|
||||
'start_date' => (string) $c['startDate'],
|
||||
'end_date' => (string) $c['endDate'],
|
||||
'channel_code' => (string) $c['channelCode'],
|
||||
'rows' => $rows,
|
||||
'note' => '与看板「合计业绩」列口径一致:按订单创建时间、剔除履约已取消(4);创建人无法映射到任一展示「中心」部门的业绩计入未归属。账号数据权限下仅列出可见创建人相关订单。',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[]|null $visibleCreatorIds 数据权限:仅统计这些创建人(null=不额外限制);须含 creator_id=0 时用 OR 条件已并入查询
|
||||
*
|
||||
* @return list<array{admin_id:int, name:string, order_count:int, amount:float}>
|
||||
*/
|
||||
private static function aggregateUnassignedByCreator(
|
||||
int $startTs,
|
||||
int $endTs,
|
||||
array $adminToPrimary,
|
||||
?array $tagDiagIds,
|
||||
?array $tagAssistantIds,
|
||||
?array $visibleCreatorIds
|
||||
): array {
|
||||
if ($tagDiagIds !== null && $tagDiagIds === []) {
|
||||
return [];
|
||||
}
|
||||
if ($tagAssistantIds !== null && $tagAssistantIds === []) {
|
||||
return [];
|
||||
}
|
||||
$query = Db::name('tcm_prescription_order')
|
||||
->alias('o')
|
||||
->whereNull('o.delete_time')
|
||||
->where('o.create_time', 'between', [$startTs, $endTs]);
|
||||
self::applyPrescriptionOrderNotCancelledForPerformance($query);
|
||||
if ($tagDiagIds !== null) {
|
||||
$query->whereIn('o.diagnosis_id', $tagDiagIds);
|
||||
}
|
||||
if ($tagAssistantIds !== null) {
|
||||
$query->whereIn('o.creator_id', array_keys($tagAssistantIds));
|
||||
}
|
||||
if ($visibleCreatorIds !== null) {
|
||||
$visibleCreatorIds = array_values(array_unique(array_filter(array_map('intval', $visibleCreatorIds), static fn (int $v): bool => $v > 0)));
|
||||
if ($visibleCreatorIds === []) {
|
||||
return [];
|
||||
}
|
||||
$ph = implode(',', array_fill(0, count($visibleCreatorIds), '?'));
|
||||
$query->whereRaw("(o.creator_id = 0 OR o.creator_id IN ({$ph}))", $visibleCreatorIds);
|
||||
}
|
||||
$query->field(['o.creator_id', 'COUNT(*) AS order_count', 'SUM(o.amount) AS amount'])
|
||||
->group('o.creator_id');
|
||||
$dbRows = $query->select()->toArray();
|
||||
if ($dbRows === []) {
|
||||
return [];
|
||||
}
|
||||
$out = [];
|
||||
foreach ($dbRows as $r) {
|
||||
$cid = (int) ($r['creator_id'] ?? 0);
|
||||
$primary = (int) ($adminToPrimary[$cid] ?? 0);
|
||||
if ($primary > 0) {
|
||||
continue;
|
||||
}
|
||||
$out[] = [
|
||||
'admin_id' => $cid,
|
||||
'name' => '',
|
||||
'order_count' => (int) ($r['order_count'] ?? 0),
|
||||
'amount' => round((float) ($r['amount'] ?? 0), 2),
|
||||
];
|
||||
}
|
||||
usort($out, static function (array $a, array $b): int {
|
||||
$c = $b['amount'] <=> $a['amount'];
|
||||
if ($c !== 0) {
|
||||
return $c;
|
||||
}
|
||||
|
||||
return $b['order_count'] <=> $a['order_count'];
|
||||
});
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $ids
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
private static function batchAdminNames(array $ids): array
|
||||
{
|
||||
if ($ids === []) {
|
||||
return [];
|
||||
}
|
||||
$rows = Db::name('admin')
|
||||
->whereIn('id', $ids)
|
||||
->whereNull('delete_time')
|
||||
->field(['id', 'name'])
|
||||
->select()
|
||||
->toArray();
|
||||
$map = [];
|
||||
foreach ($rows as $r) {
|
||||
$map[(int) $r['id']] = (string) ($r['name'] ?? '');
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表名 + 数据库前缀(用于 whereRaw 内嵌的 SQL,框架不会替换 raw 表名)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user