Files
MBTI_wang/api/app/controller/admin/Distribution.php
2026-03-17 12:39:38 +08:00

773 lines
35 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\controller\admin;
use app\BaseController;
use think\facade\Db;
use think\facade\Request;
/**
* 分销管理控制器(企业管理端)
* 路由前缀:/api/v1/admin/distribution
*/
class Distribution extends BaseController
{
// ─────────────────────────────────────────────────────────────
// GET distribution/overview
// ─────────────────────────────────────────────────────────────
public function overview()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$todayStart = strtotime(date('Y-m-d 00:00:00'));
$days = 7;
$trendStart = strtotime(date('Y-m-d 00:00:00', strtotime('-' . ($days - 1) . ' days')));
try {
$query = Db::name('commission_records')
->where('enterpriseId', $enterpriseId);
$totalCommission = (clone $query)->whereIn('status', ['paid', 'frozen'])->sum('commissionFen') ?: 0;
$paidCommission = (clone $query)->where('status', 'paid')->sum('commissionFen') ?: 0;
$frozenCommission = (clone $query)->where('status', 'frozen')->sum('commissionFen') ?: 0;
$totalOrders = (clone $query)->whereIn('status', ['paid', 'frozen'])->count();
$todayCommission = (clone $query)
->whereIn('status', ['paid', 'frozen'])
->where('createdAt', '>=', $todayStart)
->sum('commissionFen') ?: 0;
$pendingCount = (clone $query)->where('status', 'frozen')->count();
$bindingQuery = Db::name('distribution_bindings')
->where('enterpriseId', $enterpriseId)
->where('status', 'active')
->where('expireAt', '>', time());
$bindingCount = (clone $bindingQuery)->count();
$totalAgents = (clone $bindingQuery)->distinct(true)->count('inviterId');
$todayAgents = Db::name('distribution_bindings')
->where('enterpriseId', $enterpriseId)
->where('createdAt', '>=', $todayStart)
->distinct(true)
->count('inviterId');
$trendRows = Db::name('commission_records')
->where('enterpriseId', $enterpriseId)
->whereIn('status', ['paid', 'frozen'])
->where('createdAt', '>=', $trendStart)
->field("FROM_UNIXTIME(createdAt, '%Y-%m-%d') as d, SUM(commissionFen) as totalFen")
->group('d')
->order('d', 'asc')
->select()
->toArray();
$trendMap = [];
foreach ($trendRows as $row) {
$trendMap[$row['d']] = (int) ($row['totalFen'] ?? 0);
}
$commissionTrend = [];
for ($i = 0; $i < $days; $i++) {
$date = date('Y-m-d', strtotime('-' . ($days - 1 - $i) . ' days'));
$commissionTrend[] = [
'date' => $date,
'amount' => round(($trendMap[$date] ?? 0) / 100, 2),
];
}
$productSeries = self::buildProductCommissionSeries($enterpriseId);
return success([
'totalAgents' => (int) $totalAgents,
'todayAgents' => (int) $todayAgents,
'totalCommission' => number_format($totalCommission / 100, 2, '.', ''),
'todayCommission' => number_format($todayCommission / 100, 2, '.', ''),
'pendingCommission' => number_format($frozenCommission / 100, 2, '.', ''),
'pendingCount' => (int) $pendingCount,
'paidCommission' => number_format($paidCommission / 100, 2, '.', ''),
'frozenCommission' => number_format($frozenCommission / 100, 2, '.', ''),
'totalOrders' => (int) $totalOrders,
'bindingCount' => (int) $bindingCount,
'commissionTrend' => $commissionTrend,
'productCommissionSeries' => $productSeries,
]);
} catch (\Exception $e) {
return error('获取数据失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// GET distribution/distributors 分销商列表(有过邀请行为的用户)
// ─────────────────────────────────────────────────────────────
public function distributors()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$search = trim((string) Request::param('search', ''));
$page = max(1, (int) Request::param('page', 1));
$pageSize = min(100, (int) Request::param('pageSize', 20));
try {
// 找出与本企业关联的所有有过邀请行为的用户(不限 scope按 enterpriseId 筛选)
$query = Db::name('distribution_bindings')
->where('enterpriseId', $enterpriseId)
->distinct(true)
->field('inviterId')
->buildSql();
$inviterQuery = Db::name('wechat_users')
->alias('u')
->whereRaw("u.id IN {$query}")
->field('u.id, u.nickname, u.avatar, u.createdAt');
if ($search !== '') {
$inviterQuery->where(function ($q) use ($search) {
$q->where('u.nickname', 'like', "%{$search}%")
->whereOr('u.id', '=', is_numeric($search) ? (int)$search : -1);
});
}
$total = (clone $inviterQuery)->count();
$inviters = $inviterQuery->page($page, $pageSize)->select()->toArray();
$inviterIds = array_column($inviters, 'id');
// 各邀请人的累计佣金与可提现佣金
$commStats = [];
if (!empty($inviterIds)) {
$rows = Db::name('commission_records')
->whereIn('inviterId', $inviterIds)
->where('enterpriseId', $enterpriseId)
->field('inviterId,
SUM(IF(status IN ("paid","frozen"), commissionFen, 0)) as totalFen,
SUM(IF(status = "paid", commissionFen, 0)) as paidFen')
->group('inviterId')
->select()->toArray();
foreach ($rows as $r) {
$commStats[$r['inviterId']] = $r;
}
// 已提现金额
$withdrawnRows = Db::name('distribution_withdrawals')
->whereIn('userId', $inviterIds)
// 提现金额统计0=审核中,2=待收款,3=已收款
->whereIn('status', [0, 2, 3])
->field('userId, SUM(amountFen) as withdrawnFen')
->group('userId')
->select()->toArray();
$withdrawnMap = [];
foreach ($withdrawnRows as $r) {
$withdrawnMap[$r['userId']] = (int)$r['withdrawnFen'];
}
// 团队人数(绑定人数,不限 scope
$teamRows = Db::name('distribution_bindings')
->whereIn('inviterId', $inviterIds)
->where('enterpriseId', $enterpriseId)
->field('inviterId, COUNT(DISTINCT inviteeId) as teamCount')
->group('inviterId')
->select()->toArray();
$teamMap = [];
foreach ($teamRows as $r) {
$teamMap[$r['inviterId']] = (int)$r['teamCount'];
}
}
$list = [];
foreach ($inviters as $inv) {
$uid = $inv['id'];
$totalFen = (int)($commStats[$uid]['totalFen'] ?? 0);
$paidFen = (int)($commStats[$uid]['paidFen'] ?? 0);
$withdrawn = $withdrawnMap[$uid] ?? 0;
$avail = max(0, $paidFen - $withdrawn);
$list[] = [
'id' => $uid,
'agentName' => $inv['nickname'] ?: ('用户' . $uid),
'avatar' => $inv['avatar'] ?? '',
'totalCommission' => number_format($totalFen / 100, 2, '.', ''),
'availableCommission'=> number_format($avail / 100, 2, '.', ''),
'teamCount' => $teamMap[$uid] ?? 0,
'teamPerformance' => '-',
'inviteCode' => '-',
'level' => '-',
'createdAt' => $inv['createdAt'],
];
}
return success(['list' => $list, 'total' => $total, 'page' => $page, 'pageSize' => $pageSize]);
} catch (\Exception $e) {
return error('获取分销商列表失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// GET distribution/bindings 绑定记录列表
// ─────────────────────────────────────────────────────────────
public function bindings()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$page = max(1, (int) Request::param('page', 1));
$pageSize = min(100, (int) Request::param('pageSize', 20));
$status = Request::param('status', '');
$inviterId = (int) Request::param('inviterId', 0);
try {
$query = Db::name('distribution_bindings')
->alias('b')
->leftJoin('wechat_users inv', 'b.inviterId = inv.id')
->leftJoin('wechat_users invt', 'b.inviteeId = invt.id')
->field('b.*, inv.nickname as inviterName, inv.avatar as inviterAvatar,
invt.nickname as inviteeName, invt.avatar as inviteeAvatar')
->where('b.enterpriseId', $enterpriseId);
if ($inviterId > 0) {
$query->where('b.inviterId', $inviterId);
}
if ($status) {
$query->where('b.status', $status);
}
$total = (clone $query)->count();
$list = $query->order('b.updatedAt', 'desc')
->page($page, $pageSize)
->select()
->toArray();
$now = time();
foreach ($list as &$row) {
$row['remainDays'] = max(0, (int) ceil(($row['expireAt'] - $now) / 86400));
$row['inviterName'] = $row['inviterName'] ?: '未知';
$row['inviteeName'] = $row['inviteeName'] ?: '未知';
}
return success(['list' => $list, 'total' => $total, 'page' => $page, 'pageSize' => $pageSize]);
} catch (\Exception $e) {
return error('获取绑定记录失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// GET distribution/commissions 佣金记录列表
// ─────────────────────────────────────────────────────────────
public function commissions()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$page = max(1, (int) Request::param('page', 1));
$pageSize = min(100, (int) Request::param('pageSize', 20));
$status = Request::param('status', '');
$inviterId = (int) Request::param('inviterId', 0);
try {
$query = Db::name('commission_records')
->alias('c')
->leftJoin('wechat_users inv', 'c.inviterId = inv.id')
->leftJoin('wechat_users invt', 'c.inviteeId = invt.id')
->field('c.*, inv.nickname as inviterName, inv.avatar as inviterAvatar, invt.nickname as inviteeName, invt.avatar as inviteeAvatar')
->where('c.enterpriseId', $enterpriseId);
if ($inviterId > 0) {
$query->where('c.inviterId', $inviterId);
}
if ($status) {
$query->where('c.status', $status);
}
$total = (clone $query)->count();
$list = $query->order('c.createdAt', 'desc')
->page($page, $pageSize)
->select()
->toArray();
$orderIds = [];
$testResultIds = [];
foreach ($list as $row) {
if (!empty($row['orderId'])) {
$orderIds[] = (int) $row['orderId'];
}
if (!empty($row['testResultId'])) {
$testResultIds[] = (int) $row['testResultId'];
}
}
$orderTypeMap = [];
if (!empty($orderIds)) {
$rows = Db::name('test_results')
->whereIn('orderId', array_values(array_unique($orderIds)))
->field('orderId, testType')
->select()
->toArray();
foreach ($rows as $item) {
$orderTypeMap[(int) $item['orderId']] = self::normalizeTestType($item['testType'] ?? '');
}
}
$resultTypeMap = [];
if (!empty($testResultIds)) {
$rows = Db::name('test_results')
->whereIn('id', array_values(array_unique($testResultIds)))
->field('id, testType')
->select()
->toArray();
foreach ($rows as $item) {
$resultTypeMap[(int) $item['id']] = self::normalizeTestType($item['testType'] ?? '');
}
}
foreach ($list as &$row) {
$testType = 'other';
if (($row['commissionSource'] ?? '') === 'test_completion' && !empty($row['testResultId'])) {
$testType = $resultTypeMap[(int) $row['testResultId']] ?? 'other';
} elseif (!empty($row['orderId'])) {
$testType = $orderTypeMap[(int) $row['orderId']] ?? 'other';
}
$row['testType'] = $testType;
$row['testTypeLabel'] = self::getTestTypeLabel($testType);
$row['commissionYuan'] = number_format($row['commissionFen'] / 100, 2, '.', '');
$row['orderYuan'] = number_format($row['orderAmount'] / 100, 2, '.', '');
}
return success(['list' => $list, 'total' => $total, 'page' => $page, 'pageSize' => $pageSize]);
} catch (\Exception $e) {
return error('获取佣金记录失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// GET distribution/withdrawals 提现申请列表
// ─────────────────────────────────────────────────────────────
public function withdrawals()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$page = max(1, (int) Request::param('page', 1));
$pageSize = min(100, (int) Request::param('pageSize', 20));
$status = Request::param('status', '');
try {
$query = Db::name('distribution_withdrawals')
->alias('w')
->join('wechat_users u', 'w.userId = u.id')
->field('w.*, u.nickname, u.avatar')
->where('u.enterpriseId', $enterpriseId);
if ($status !== '') {
// 后台传入可以是字符串或数字,这里统一转 int
$query->where('w.status', (int)$status);
}
$total = (clone $query)->count();
$list = $query->order('w.createdAt', 'desc')
->page($page, $pageSize)
->select()
->toArray();
foreach ($list as &$row) {
$row['amountYuan'] = number_format($row['amountFen'] / 100, 2, '.', '');
$row['nickname'] = $row['nickname'] ?: '未知用户';
// 确保前端拿到的是数字 status避免 '0' 和 0 比较异常)
$code = (int) ($row['status'] ?? 0);
$row['status'] = $code;
// 统一后台状态文案0审核中、1已驳回、2待收款、3已收款、4已过期
switch ($code) {
case 0:
$row['statusLabel'] = '审核中';
break;
case 1:
$row['statusLabel'] = '已驳回';
break;
case 2:
$row['statusLabel'] = '待收款';
break;
case 3:
$row['statusLabel'] = '已收款';
break;
case 4:
$row['statusLabel'] = '已过期';
break;
default:
$row['statusLabel'] = '未知';
break;
}
}
return success(['list' => $list, 'total' => $total, 'page' => $page, 'pageSize' => $pageSize]);
} catch (\Exception $e) {
return error('获取提现记录失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// POST distribution/withdrawals/:id/approve 审核通过
// ─────────────────────────────────────────────────────────────
public function approveWithdrawal(int $id)
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$note = Request::param('note', '');
$now = time();
$record = Db::name('distribution_withdrawals')
->alias('w')
->join('wechat_users u', 'w.userId = u.id')
->where('w.id', $id)
->where('u.enterpriseId', $enterpriseId)
->field('w.*, u.openid')
->find();
// 仅允许处理审核中status=0的记录
if (!$record || (int)$record['status'] !== 0) {
return error('提现申请不存在、已处理或无权限', 400);
}
try {
// 生成商户明细单号TX + 时间戳 + 随机数示例TX202603121526520005
$outDetailNo = 'TX' . date('YmdHis') . mt_rand(1000, 9999);
// 调用微信商家转账到零钱接口
$service = new \app\common\service\WechatTransferService();
$result = $service->createTransfer([
'out_detail_no' => $outDetailNo,
'transfer_amount'=> (int) $record['amountFen'],
'transfer_remark'=> '推广佣金提现',
'openid' => $record['openid'],
'batch_name' => '推广佣金提现',
'batch_remark' => '用户提现',
]);
if ($result['success'] !== true) {
$err = $result['error'] ?? [];
$code = $err['code'] ?? 'UNKNOWN';
$msg = $err['message'] ?? '微信转账接口调用失败';
return error("微信转账发起失败({$code}{$msg}", 500);
}
$wechatData = $result['data'] ?? [];
Db::name('distribution_withdrawals')
->where('id', $id)
->update([
// 2=待收款(已发起微信转账,等待用户确认)
'status' => 2,
'auditNote' => $note,
'auditAt' => $now,
'updatedAt' => $now,
'pay_type' => 'wechat',
'out_bill_no' => $outDetailNo,
'transfer_bill_no' => $wechatData['batch_id'] ?? null,
'wechat_pay_state' => $wechatData['batch_status'] ?? 'PROCESSING',
'transfer_scene_id'=> $wechatData['transfer_scene_id'] ?? env('TRANSFER_SCENE_ID', '1005'),
'mch_id' => env('MCH_ID', null),
]);
return success(null, '审核通过,已发起微信转账');
} catch (\Exception $e) {
return error('操作失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// POST distribution/withdrawals/:id/reject 审核拒绝
// ─────────────────────────────────────────────────────────────
public function rejectWithdrawal(int $id)
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$note = Request::param('note', '');
$now = time();
$record = Db::name('distribution_withdrawals')
->alias('w')
->join('wechat_users u', 'w.userId = u.id')
->where('w.id', $id)
->where('u.enterpriseId', $enterpriseId)
->field('w.*')
->find();
// 仅允许处理审核中status=0的记录
if (!$record || (int)$record['status'] !== 0) {
return error('提现申请不存在、已处理或无权限', 400);
}
Db::startTrans();
try {
// 退回余额
Db::name('wechat_users')
->where('id', $record['userId'])
->inc('walletBalance', $record['amountFen'])
->update(['updatedAt' => $now]);
Db::name('distribution_withdrawals')
->where('id', $id)
->update([
// 1=已驳回
'status' => 1,
'auditNote' => $note,
'auditAt' => $now,
'updatedAt' => $now,
]);
Db::commit();
return success(null, '已拒绝,余额已退回');
} catch (\Exception $e) {
Db::rollback();
return error('操作失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// GET distribution/settings 获取企业分销配置
// ─────────────────────────────────────────────────────────────
public function settings()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
try {
$config = Db::name('system_config')
->where('key', 'distribution')
->where('enterprise_id', $enterpriseId)
->find();
$tsDefault = self::defaultTestSettings();
$default = [
'enabled' => true,
'promoCenterTitle' => '推广中心',
'bindingDays' => 30,
'testSettings' => $tsDefault,
];
if ($config && $config['value']) {
$settings = is_string($config['value']) ? json_decode($config['value'], true) : $config['value'];
$settings = array_merge($default, $settings ?? []);
} else {
$settings = $default;
}
// 附加前端可读的 commissionAmount
$settings['testSettings'] = self::appendTestSettingsAmount(
$settings['testSettings'] ?? $tsDefault
);
return success($settings);
} catch (\Exception $e) {
return error('获取配置失败:' . $e->getMessage(), 500);
}
}
// ─────────────────────────────────────────────────────────────
// PUT distribution/settings 更新企业分销配置
// ─────────────────────────────────────────────────────────────
public function updateSettings()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限', 403);
}
$enterpriseId = (int) ($user['enterpriseId'] ?? 0);
$settings = Request::only(['enabled', 'promoCenterTitle', 'bindingDays', 'testSettings']);
$promoTitle = trim((string)($settings['promoCenterTitle'] ?? ''));
$toSave = [
'enabled' => (bool)($settings['enabled'] ?? true),
'promoCenterTitle' => $promoTitle !== '' ? $promoTitle : '推广中心',
'bindingDays' => (int)($settings['bindingDays'] ?? 30),
'testSettings' => self::sanitizeTestSettings($settings['testSettings'] ?? null),
];
try {
$now = time();
$existing = Db::name('system_config')
->where('key', 'distribution')
->where('enterprise_id', $enterpriseId)
->find();
if ($existing) {
Db::name('system_config')
->where('key', 'distribution')
->where('enterprise_id', $enterpriseId)
->update(['value' => json_encode($toSave, JSON_UNESCAPED_UNICODE), 'updatedAt' => $now]);
} else {
Db::name('system_config')->insert([
'key' => 'distribution',
'enterprise_id' => $enterpriseId,
'value' => json_encode($toSave, JSON_UNESCAPED_UNICODE),
'createdAt' => $now,
'updatedAt' => $now,
]);
}
$toSave['testSettings'] = self::appendTestSettingsAmount($toSave['testSettings']);
return success($toSave, '配置已保存');
} catch (\Exception $e) {
return error('保存配置失败:' . $e->getMessage(), 500);
}
}
private static function defaultTestSettings(): array
{
$item = ['enabled' => true, 'commissionType' => 'ratio', 'commissionRate' => 90, 'commissionAmountFen' => 0, 'noPayment' => false];
return ['face' => $item, 'mbti' => $item, 'disc' => $item, 'pdp' => $item];
}
private static function sanitizeTestSettings($raw): array
{
$default = self::defaultTestSettings();
if (!is_array($raw)) return $default;
$result = [];
foreach ($default as $type => $def) {
$s = $raw[$type] ?? [];
$commissionType = in_array($s['commissionType'] ?? '', ['ratio', 'amount']) ? $s['commissionType'] : 'ratio';
$amountFen = isset($s['commissionAmount'])
? (int) round((float)$s['commissionAmount'] * 100)
: (int)($s['commissionAmountFen'] ?? 0);
$rate = max(0, min(100, (int)($s['commissionRate'] ?? 90)));
$result[$type] = [
'enabled' => ($s['enabled'] ?? true) !== false,
'commissionType' => $commissionType,
'commissionRate' => $commissionType === 'ratio' ? $rate : 0,
'commissionAmountFen'=> $commissionType === 'amount' ? max(0, $amountFen) : 0,
'noPayment' => !empty($s['noPayment']),
];
}
return $result;
}
private static function appendTestSettingsAmount(array $ts): array
{
foreach ($ts as $k => $v) {
$ts[$k]['commissionAmount'] = round(($v['commissionAmountFen'] ?? 0) / 100, 2);
}
return $ts;
}
private static function buildProductCommissionSeries(int $enterpriseId): array
{
$records = Db::name('commission_records')
->where('enterpriseId', $enterpriseId)
->whereIn('status', ['paid', 'frozen'])
->field('orderId, testResultId, commissionSource, commissionFen')
->select()
->toArray();
$orderIds = [];
$testResultIds = [];
foreach ($records as $record) {
if (!empty($record['orderId'])) {
$orderIds[] = (int) $record['orderId'];
}
if (!empty($record['testResultId'])) {
$testResultIds[] = (int) $record['testResultId'];
}
}
$orderTypeMap = [];
if (!empty($orderIds)) {
$rows = Db::name('test_results')
->whereIn('orderId', array_values(array_unique($orderIds)))
->field('orderId, testType')
->select()
->toArray();
foreach ($rows as $row) {
$orderTypeMap[(int) $row['orderId']] = self::normalizeTestType($row['testType'] ?? '');
}
}
$resultTypeMap = [];
if (!empty($testResultIds)) {
$rows = Db::name('test_results')
->whereIn('id', array_values(array_unique($testResultIds)))
->field('id, testType')
->select()
->toArray();
foreach ($rows as $row) {
$resultTypeMap[(int) $row['id']] = self::normalizeTestType($row['testType'] ?? '');
}
}
$totals = [
'face' => 0,
'mbti' => 0,
'disc' => 0,
'pdp' => 0,
'other' => 0,
];
foreach ($records as $record) {
$type = 'other';
if (($record['commissionSource'] ?? '') === 'test_completion' && !empty($record['testResultId'])) {
$type = $resultTypeMap[(int) $record['testResultId']] ?? 'other';
} elseif (!empty($record['orderId'])) {
$type = $orderTypeMap[(int) $record['orderId']] ?? 'other';
}
if (!isset($totals[$type])) {
$type = 'other';
}
$totals[$type] += (int) ($record['commissionFen'] ?? 0);
}
return [
['label' => '人脸分析', 'value' => round($totals['face'] / 100, 2)],
['label' => 'MBTI', 'value' => round($totals['mbti'] / 100, 2)],
['label' => 'DISC', 'value' => round($totals['disc'] / 100, 2)],
['label' => 'PDP', 'value' => round($totals['pdp'] / 100, 2)],
['label' => '其他', 'value' => round($totals['other'] / 100, 2)],
];
}
private static function normalizeTestType(string $testType): string
{
$normalized = strtolower(trim($testType));
if ($normalized === 'ai') {
return 'face';
}
if (in_array($normalized, ['face', 'mbti', 'disc', 'pdp'], true)) {
return $normalized;
}
return 'other';
}
private static function getTestTypeLabel(string $testType): string
{
$map = [
'face' => '人脸',
'mbti' => 'MBTI',
'disc' => 'DISC',
'pdp' => 'PDP',
'other' => '其他',
];
return $map[$testType] ?? strtoupper($testType ?: '其他');
}
}