Files
MBTI_wang/api/app/controller/admin/Order.php
Ghost 3fdf9b6ed2 chore: 管理端与 API 批量更新(测评恢复、看板、分销与用户)
1、修复了用户详情/测评结果与人脸结果解析展示问题;管理端订单、分销及超管用户相关接口与展示异常。

2、新增了 testResultParse 统一解析工具、mbti_test_results 恢复 SQL 及生成脚本;补充 API 路由与 Dashboard/用户侧能力。

3、优化了企业/超管数据看板与分销结算逻辑;精简超管 Settings 与布局代码;完善 faceResultDetail;小程序 app.js 小幅同步。

Made-with: Cursor
2026-03-31 10:56:28 +08:00

185 lines
7.0 KiB
PHP

<?php
namespace app\controller\admin;
use app\BaseController;
use think\facade\Db;
use think\facade\Request;
/**
* 管理端订单列表(只读),包含用户信息与关联的测试数据
*/
class Order extends BaseController
{
/**
* 订单列表:分页、关键词、状态/产品筛选;企业管理员仅本企业订单
* GET /api/v1/admin/orders?page=1&pageSize=20&keyword=&status=&productType=
*/
public function index()
{
$user = $this->request->user ?? null;
if (!$user) {
return error('未登录', 401);
}
if (!in_array($user['role'] ?? '', ['admin', 'enterprise_admin', 'superadmin'])) {
return error('无权限访问', 403);
}
$page = (int) Request::param('page', 1);
$pageSize = (int) Request::param('pageSize', 20);
$pageSize = min(max($pageSize, 1), 100);
$keyword = trim(Request::param('keyword', ''));
$status = trim(Request::param('status', ''));
$productType = trim(Request::param('productType', ''));
// 超管:全平台订单;其余管理员仅本企业
$enterpriseId = null;
if (($user['role'] ?? '') !== 'superadmin') {
$enterpriseId = $user['enterpriseId'] ?? null;
if (!$enterpriseId) {
$adminRow = Db::name('users')->where('id', $user['userId'] ?? 0)->find();
$enterpriseId = $adminRow['enterpriseId'] ?? null;
}
}
$query = Db::name('orders');
if ($enterpriseId !== null) {
$query->where('enterpriseId', $enterpriseId);
}
if ($status !== '') {
$query->where('status', $status);
}
if ($productType !== '') {
$query->where('productType', $productType);
}
if ($keyword !== '') {
if (is_numeric($keyword)) {
$query->where(function ($q) use ($keyword) {
$q->whereLike('orderNo', '%' . $keyword . '%')->whereOr('userId', (int) $keyword);
});
} else {
$userIdsMatch = Db::name('wechat_users')->where('nickname|phone', 'like', '%' . $keyword . '%')->column('id');
$userIdsMatch = array_values(array_filter($userIdsMatch));
$query->where(function ($q) use ($keyword, $userIdsMatch) {
$q->whereLike('orderNo', '%' . $keyword . '%');
if (!empty($userIdsMatch)) {
$q->whereOr('userId', 'in', $userIdsMatch);
}
});
}
}
// 与列表相同筛选条件下的全量统计(非当前页):已支付/已完成单数、实收金额(分)
$paidCompletedCount = (int) (clone $query)->whereIn('status', ['paid', 'completed'])->count();
$totalRevenueFen = (int) (clone $query)->whereIn('status', ['paid', 'completed'])->sum('amount');
$query->order('createdAt', 'desc');
$total = (int) (clone $query)->count();
$list = (clone $query)->page($page, $pageSize)->select()->toArray();
$userIds = array_values(array_unique(array_filter(array_column($list, 'userId'))));
$usersMap = [];
if (!empty($userIds)) {
$users = Db::name('wechat_users')
->where('id', 'in', $userIds)
->field('id, nickname, phone')
->select()
->toArray();
foreach ($users as $u) {
$usersMap[(int) $u['id']] = $u;
}
}
$orderIds = array_column($list, 'id');
$testsByOrder = [];
if (!empty($orderIds)) {
$tests = Db::name('test_results')
->where('orderId', 'in', $orderIds)
->field('id, orderId, userId, testType, resultData, createdAt')
->order('createdAt', 'desc')
->select()
->toArray();
foreach ($tests as $t) {
$oid = (int) ($t['orderId'] ?? 0);
if ($oid <= 0) {
continue;
}
if (!isset($testsByOrder[$oid])) {
$testsByOrder[$oid] = [];
}
$raw = $t['resultData'] ?? '';
$resultStr = is_string($raw) ? $raw : json_encode($raw, JSON_UNESCAPED_UNICODE);
$testsByOrder[$oid][] = [
'id' => (int) $t['id'],
'testType' => $t['testType'] ?? '',
'resultSummary' => $this->extractResultSummary($t['testType'] ?? '', $resultStr),
'createdAt' => isset($t['createdAt']) ? (int) $t['createdAt'] : null,
];
}
}
foreach ($list as &$row) {
$uid = (int) ($row['userId'] ?? 0);
$u = $usersMap[$uid] ?? null;
$row['userName'] = $u ? ($u['nickname'] ?? ('用户' . $uid)) : ('用户' . $uid);
$row['userPhone'] = $u ? ($u['phone'] ?? '') : '';
$row['testData'] = $testsByOrder[$row['id']] ?? [];
}
return success([
'list' => $list,
'total' => $total,
'page' => $page,
'pageSize' => $pageSize,
'hasMore' => ($page * $pageSize) < $total,
// 看板卡片:全量口径(随 keyword / status / productType / 企业 筛选变化,与 total 一致)
'paidCompletedCount' => $paidCompletedCount,
'totalRevenueFen' => $totalRevenueFen,
]);
}
/**
* 从 resultData 字符串中提取简要结果(用于列表展示)
*/
private function extractResultSummary(string $testType, string $resultStr): string
{
if ($resultStr === '') {
return '-';
}
$data = json_decode($resultStr, true);
if (!is_array($data)) {
return mb_substr($resultStr, 0, 30) . (mb_strlen($resultStr) > 30 ? '…' : '');
}
$type = strtolower($testType);
if ($type === 'mbti') {
return (string) ($data['mbtiType'] ?? $data['type'] ?? $data['result'] ?? '');
}
if ($type === 'disc') {
$desc = $data['description']['type'] ?? null;
if (is_string($desc) && $desc !== '') {
return $desc;
}
if (!empty($data['dominantType'])) {
return (string) $data['dominantType'] . '型';
}
return (string) ($data['disc'] ?? '');
}
if ($type === 'pdp') {
$desc = $data['description']['type'] ?? null;
if (is_string($desc) && $desc !== '') {
return $desc;
}
if (!empty($data['dominantType'])) {
return (string) $data['dominantType'];
}
return (string) ($data['pdp'] ?? '');
}
if ($type === 'face' || $type === 'ai') {
return '人脸分析';
}
return (string) ($data['type'] ?? $data['result'] ?? '');
}
}