chore: 首次提交 - 关联 GitHub fnvtk/MBTI_wang

Made-with: Cursor
This commit is contained in:
卡若
2026-03-17 12:39:38 +08:00
commit eb510304c0
259 changed files with 60464 additions and 0 deletions

View File

@@ -0,0 +1,772 @@
<?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 ?: '其他');
}
}