feat: 第三方渠道上下文与开放平台服务接入
1、修复了企业版/个人版在第三方入口下的人脸与测评跳转问题。 2、新增 ThirdPartyChannel/OpenPlatformService 及上下文 thirdPartyContext,补充相关迁移。 3、调整 Analyze/Auth/Test 等接口与小程序入口逻辑。 Made-with: Cursor
This commit is contained in:
271
api/app/common/service/OpenPlatformService.php
Normal file
271
api/app/common/service/OpenPlatformService.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\PdpDiscResultText;
|
||||
use think\facade\Db;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 第三方开放平台:按手机号回写测评结果(POST /api/open)
|
||||
* 仅当用户存在渠道绑定字段且配置了 OPEN_PLATFORM_URL / OPEN_PLATFORM_API_KEY 时推送
|
||||
*/
|
||||
class OpenPlatformService
|
||||
{
|
||||
public static function hasThirdPartyBinding(int $userId): bool
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return false;
|
||||
}
|
||||
$u = Db::name('wechat_users')
|
||||
->where('id', $userId)
|
||||
->field('ext_uid,third_party_phone')
|
||||
->find();
|
||||
if (!$u) {
|
||||
return false;
|
||||
}
|
||||
foreach (['ext_uid', 'third_party_phone'] as $k) {
|
||||
if (trim((string) ($u[$k] ?? '')) !== '') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开放平台要求的 phone:**优先 third_party_phone**,无则回落主库 phone
|
||||
*/
|
||||
public static function resolveNotifyPhone(array $wechatRow): ?string
|
||||
{
|
||||
$tp = trim((string) ($wechatRow['third_party_phone'] ?? ''));
|
||||
$main = trim((string) ($wechatRow['phone'] ?? ''));
|
||||
$norm = ThirdPartyChannelService::normalizePhone($tp !== '' ? $tp : $main);
|
||||
if ($norm !== null) {
|
||||
return $norm;
|
||||
}
|
||||
$digits = preg_replace('/\D+/', '', $tp !== '' ? $tp : $main);
|
||||
if ($digits !== '' && strlen($digits) >= 5 && strlen($digits) <= 20) {
|
||||
return $digits;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从本次提交的 result 数组生成开放平台单字段摘要
|
||||
*
|
||||
* @return array<string,string> 如 ['mbti'=>'INTJ'],失败返回 []
|
||||
*/
|
||||
public static function buildAssessmentPayload(string $testType, array $result): array
|
||||
{
|
||||
$testType = strtolower(trim($testType));
|
||||
if (!in_array($testType, ['mbti', 'disc', 'pdp', 'face', 'ai'], true)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($testType === 'face' || $testType === 'ai') {
|
||||
$mbtiShort = '';
|
||||
if (isset($result['mbti']['type'])) {
|
||||
$mbtiShort = trim((string) $result['mbti']['type']);
|
||||
} elseif (isset($result['mbti']) && !is_array($result['mbti'])) {
|
||||
$mbtiShort = trim((string) $result['mbti']);
|
||||
}
|
||||
if ($mbtiShort !== '') {
|
||||
$mbtiShort = self::formatMbtiForOpenPlatform($mbtiShort);
|
||||
if ($mbtiShort === '') {
|
||||
return [];
|
||||
}
|
||||
if (mb_strlen($mbtiShort) > 500) {
|
||||
$mbtiShort = mb_substr($mbtiShort, 0, 500) . '…';
|
||||
}
|
||||
|
||||
return ['mbti' => $mbtiShort];
|
||||
}
|
||||
$fa = $result['faceAnalysis'] ?? '';
|
||||
if (is_string($fa) && trim($fa) !== '') {
|
||||
$fa = preg_replace('/\s+/u', ' ', trim($fa));
|
||||
$snippet = mb_strlen($fa) > 500 ? mb_substr($fa, 0, 500) . '…' : $fa;
|
||||
|
||||
return ['mbti' => $snippet];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
$text = '';
|
||||
switch ($testType) {
|
||||
case 'mbti':
|
||||
$t = $result['mbtiType'] ?? $result['mbti'] ?? '';
|
||||
$raw = is_string($t) ? trim($t) : (is_numeric($t) ? (string) $t : '');
|
||||
$text = self::formatMbtiForOpenPlatform($raw);
|
||||
break;
|
||||
case 'disc':
|
||||
$text = PdpDiscResultText::discTopTwo($result);
|
||||
if ($text === '') {
|
||||
$dominantType = $result['dominantType'] ?? $result['disc'] ?? '';
|
||||
$text = (is_string($dominantType) || is_numeric($dominantType) ? (string) $dominantType : '') . '型';
|
||||
}
|
||||
$text = self::formatDiscForOpenPlatform($text);
|
||||
break;
|
||||
case 'pdp':
|
||||
$text = PdpDiscResultText::pdpTopTwo($result);
|
||||
if ($text === '') {
|
||||
$text = (string) ($result['description']['type'] ?? $result['pdp'] ?? '');
|
||||
}
|
||||
$text = self::formatPdpForOpenPlatform($text);
|
||||
break;
|
||||
}
|
||||
$text = trim($text);
|
||||
if ($text === '') {
|
||||
return [];
|
||||
}
|
||||
if (mb_strlen($text) > 500) {
|
||||
$text = mb_substr($text, 0, 500) . '…';
|
||||
}
|
||||
|
||||
return [$testType => $text];
|
||||
}
|
||||
|
||||
/**
|
||||
* 测评结果写入成功后调用:mbti/disc/pdp/face(ai),且用户有第三方绑定(ext_uid 或 third_party_phone)
|
||||
*
|
||||
* 开放平台仅接收 mbti/disc/pdp:人脸结果优先推推断的 MBTI;无则推 faceAnalysis 摘要到 mbti 字段
|
||||
*
|
||||
* @param array<string,mixed> $result 与写入 test_results 前相同的数组
|
||||
*/
|
||||
public static function notifyQuestionnaireIfNeeded(int $userId, string $testType, $result): void
|
||||
{
|
||||
if ($userId <= 0 || !is_array($result)) {
|
||||
return;
|
||||
}
|
||||
$testType = strtolower(trim($testType));
|
||||
if (!in_array($testType, ['mbti', 'disc', 'pdp', 'face', 'ai'], true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$baseUrl = trim((string) env('OPEN_PLATFORM_URL', ''));
|
||||
$apiKey = trim((string) env('OPEN_PLATFORM_API_KEY', ''));
|
||||
if ($baseUrl === '' || $apiKey === '') {
|
||||
return;
|
||||
}
|
||||
if (!self::hasThirdPartyBinding($userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wechatRow = Db::name('wechat_users')
|
||||
->where('id', $userId)
|
||||
->field('phone,third_party_phone')
|
||||
->find();
|
||||
if (!$wechatRow) {
|
||||
return;
|
||||
}
|
||||
$phone = self::resolveNotifyPhone($wechatRow);
|
||||
if ($phone === null || $phone === '') {
|
||||
Log::warning('OpenPlatform skip: no phone', ['userId' => $userId]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$assessment = self::buildAssessmentPayload($testType, $result);
|
||||
if ($assessment === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = rtrim(trim($baseUrl), '/');
|
||||
if (!preg_match('#/api/open/user/profile$#', $url)) {
|
||||
$url .= '/api/open/user/profile';
|
||||
}
|
||||
|
||||
|
||||
|
||||
$body = array_merge(['phone' => $phone], $assessment);
|
||||
$headers = [
|
||||
// requestCurl 对 SSL 默认会关闭校验,避免「找不到本地 issuer certificate」阻断对接
|
||||
'Content-Type:application/json',
|
||||
'Authorization: Bearer ' . $apiKey
|
||||
];
|
||||
try {
|
||||
$respBody = \requestCurl($url, $body, 'POST', $headers, 'json');
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('OpenPlatform requestCurl exception: ' . $e->getMessage(), [
|
||||
'userId' => $userId,
|
||||
'url' => $url,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_string($respBody)) {
|
||||
$respBody = '';
|
||||
}
|
||||
if ($respBody === '') {
|
||||
// requestCurl 没返回 http code,这里只做响应为空的弱提示
|
||||
Log::warning('OpenPlatform empty response', [
|
||||
'userId' => $userId,
|
||||
'url' => $url,
|
||||
'body' => [
|
||||
'phone' => $phone,
|
||||
// 只回显 keys,避免日志把完整结果打爆
|
||||
'keys' => array_keys($assessment),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MBTI:四字母类型,如 ENFJ(兼容文案中带 ENFJ-A、括号等)
|
||||
*/
|
||||
private static function formatMbtiForOpenPlatform(string $raw): string
|
||||
{
|
||||
$raw = trim($raw);
|
||||
if ($raw === '') {
|
||||
return '';
|
||||
}
|
||||
if (preg_match('/\b([EI][NS][FT][JP])\b/i', $raw, $m)) {
|
||||
return strtoupper($m[1]);
|
||||
}
|
||||
$compact = strtoupper(preg_replace('/[^EINSFTPJ]/i', '', $raw));
|
||||
if (strlen($compact) >= 4 && preg_match('/^[EI][NS][FT][JP]$/', substr($compact, 0, 4))) {
|
||||
return substr($compact, 0, 4);
|
||||
}
|
||||
$letters = strtoupper(preg_replace('/[^A-Z]/', '', $raw));
|
||||
if (strlen($letters) >= 4) {
|
||||
return substr($letters, 0, 4);
|
||||
}
|
||||
|
||||
return $raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* DISC:D+C(去掉尾缀「型」)
|
||||
*/
|
||||
private static function formatDiscForOpenPlatform(string $text): string
|
||||
{
|
||||
$text = trim($text);
|
||||
if ($text === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return preg_replace('/型$/u', '', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* PDP:无尾熊+变色龙(各段去掉尾缀「型」)
|
||||
*/
|
||||
private static function formatPdpForOpenPlatform(string $text): string
|
||||
{
|
||||
$text = trim($text);
|
||||
if ($text === '') {
|
||||
return '';
|
||||
}
|
||||
$parts = preg_split('/\+/u', $text, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$parts = array_map(static function ($p) {
|
||||
return preg_replace('/型$/u', '', trim($p));
|
||||
}, $parts);
|
||||
$parts = array_values(array_filter($parts, static function ($p) {
|
||||
return $p !== '';
|
||||
}));
|
||||
|
||||
return implode('+', $parts);
|
||||
}
|
||||
}
|
||||
113
api/app/common/service/ThirdPartyChannelService.php
Normal file
113
api/app/common/service/ThirdPartyChannelService.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 第三方渠道透传:userid / phone / tid 解析与 wechat_users 写入(仅存用户表)
|
||||
*/
|
||||
class ThirdPartyChannelService
|
||||
{
|
||||
public static function parseFromRequestArray(array $input): array
|
||||
{
|
||||
$tp = $input['thirdParty'] ?? null;
|
||||
if (!is_array($tp)) {
|
||||
return ['userid' => '', 'phone' => '', 'tid' => ''];
|
||||
}
|
||||
$userid = isset($tp['userid']) ? trim((string) $tp['userid']) : '';
|
||||
$phone = isset($tp['phone']) ? trim((string) $tp['phone']) : '';
|
||||
$tid = isset($tp['tid']) ? trim((string) $tp['tid']) : '';
|
||||
return [
|
||||
'userid' => $userid,
|
||||
'phone' => $phone,
|
||||
'tid' => $tid,
|
||||
];
|
||||
}
|
||||
|
||||
public static function normalizePhone(?string $raw): ?string
|
||||
{
|
||||
if ($raw === null || $raw === '') {
|
||||
return null;
|
||||
}
|
||||
$digits = preg_replace('/\D+/', '', (string) $raw);
|
||||
if ($digits === '') {
|
||||
return null;
|
||||
}
|
||||
if (strlen($digits) > 11 && substr($digits, 0, 2) === '86') {
|
||||
$digits = substr($digits, -11);
|
||||
}
|
||||
if (strlen($digits) < 5 || strlen($digits) > 20) {
|
||||
return null;
|
||||
}
|
||||
return $digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按主手机号列查找用户(规范化后比对)
|
||||
*
|
||||
* @return array|null 表行
|
||||
*/
|
||||
public static function findUserByNormalizedPhone(string $norm): ?array
|
||||
{
|
||||
if ($norm === '') {
|
||||
return null;
|
||||
}
|
||||
$row = Db::name('wechat_users')->where('phone', $norm)->find();
|
||||
if ($row) {
|
||||
return $row;
|
||||
}
|
||||
$candidates = Db::name('wechat_users')
|
||||
->whereNotNull('phone')
|
||||
->where('phone', '<>', '')
|
||||
->where('phone', 'like', '%' . $norm)
|
||||
->limit(50)
|
||||
->select()
|
||||
->toArray();
|
||||
foreach ($candidates as $r) {
|
||||
if (self::normalizePhone($r['phone'] ?? '') === $norm) {
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并第三方字段到指定用户行(有传则写)
|
||||
* - 有渠道 phone:始终更新 third_party_phone(含老用户命中手机号与透传一致时)
|
||||
* - 主字段 phone 为空时:用渠道号码写入 phone(新号、未绑手机用户)
|
||||
*/
|
||||
public static function applyToUserId(int $userId, array $thirdParty): void
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
$data = [];
|
||||
if ($thirdParty['userid'] !== '') {
|
||||
$data['ext_uid'] = mb_substr($thirdParty['userid'], 0, 191);
|
||||
}
|
||||
if ($thirdParty['tid'] !== '') {
|
||||
$data['third_party_tid'] = mb_substr($thirdParty['tid'], 0, 191);
|
||||
}
|
||||
|
||||
$norm = null;
|
||||
if ($thirdParty['phone'] !== '') {
|
||||
$norm = self::normalizePhone($thirdParty['phone']);
|
||||
}
|
||||
if ($norm !== null) {
|
||||
$data['third_party_phone'] = mb_substr($norm, 0, 32);
|
||||
$row = Db::name('wechat_users')->where('id', $userId)->field('phone')->find();
|
||||
$mainPhone = trim((string) ($row['phone'] ?? ''));
|
||||
if ($mainPhone === '') {
|
||||
$data['phone'] = mb_substr($norm, 0, 20);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
return;
|
||||
}
|
||||
$data['updatedAt'] = time();
|
||||
Db::name('wechat_users')->where('id', $userId)->update($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -208,6 +208,14 @@ class Analyze extends BaseController
|
||||
} catch (\Throwable $e) {
|
||||
// 上报失败不阻断
|
||||
}
|
||||
|
||||
try {
|
||||
if (is_array($storePayload)) {
|
||||
\app\common\service\OpenPlatformService::notifyQuestionnaireIfNeeded($userId, 'face', $storePayload);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 第三方开放平台失败不阻断
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 写入失败不影响返回分析结果
|
||||
|
||||
@@ -7,6 +7,7 @@ use app\model\WechatUser;
|
||||
use app\common\service\JwtService;
|
||||
use app\common\service\WechatService;
|
||||
use app\common\service\FeishuLeadWebhookService;
|
||||
use app\common\service\ThirdPartyChannelService;
|
||||
use think\facade\Request;
|
||||
use think\facade\Db;
|
||||
|
||||
@@ -206,35 +207,104 @@ class Auth extends BaseController
|
||||
|
||||
/**
|
||||
* 微信小程序登录:code 换 openid,查/建用户,返回 token 与用户信息
|
||||
* POST api/auth/wechat body: { "code": "xxx" }
|
||||
* POST api/auth/wechat body: { "code", "enterpriseId"?, "thirdParty"?: { "userid","phone","tid" } }
|
||||
* 第三方 phone 命中已有主手机号用户时:不新建行;openid 绑到该用户(详见 ThirdPartyChannelService)
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function wechatLogin()
|
||||
{
|
||||
$code = Request::param('code', '');
|
||||
$rawContent = Request::getContent();
|
||||
$input = [];
|
||||
if ($rawContent !== '') {
|
||||
$input = json_decode($rawContent, true) ?: [];
|
||||
}
|
||||
if ($input === []) {
|
||||
$input = Request::post() ?: Request::param();
|
||||
}
|
||||
|
||||
$code = $input['code'] ?? Request::param('code', '');
|
||||
if ($code === '') {
|
||||
return error('缺少 code', 400);
|
||||
}
|
||||
|
||||
$thirdParty = ThirdPartyChannelService::parseFromRequestArray(is_array($input) ? $input : []);
|
||||
$loginEnterpriseId = isset($input['enterpriseId']) && (int) $input['enterpriseId'] > 0
|
||||
? (int) $input['enterpriseId']
|
||||
: null;
|
||||
|
||||
$session = WechatService::jscode2session($code);
|
||||
if (isset($session['errcode']) && $session['errcode'] !== 0) {
|
||||
return error($session['errmsg'] ?? '微信登录失败', 400);
|
||||
}
|
||||
|
||||
$openid = $session['openid'];
|
||||
//$openid = 'oucCB15WDKCdwfNo-fpyS72iY5IQ';
|
||||
$openid = $session['openid'];
|
||||
$sessionKey = $session['session_key'] ?? '';
|
||||
$unionid = $session['unionid'] ?? null;
|
||||
$unionid = $session['unionid'] ?? null;
|
||||
|
||||
$wechatUser = Db::name('wechat_users')->where('openid', $openid)->find();
|
||||
$now = time();
|
||||
$ip = Request::ip();
|
||||
$ip = Request::ip();
|
||||
|
||||
$loginEnterpriseId = isset($input['enterpriseId']) && (int) $input['enterpriseId'] > 0
|
||||
? (int) $input['enterpriseId']
|
||||
$userByOpenid = Db::name('wechat_users')->where('openid', $openid)->find();
|
||||
$phoneNorm = ThirdPartyChannelService::normalizePhone($thirdParty['phone']);
|
||||
$userByPhone = $phoneNorm !== null
|
||||
? ThirdPartyChannelService::findUserByNormalizedPhone($phoneNorm)
|
||||
: null;
|
||||
|
||||
if ($wechatUser) {
|
||||
$wechatUser = null;
|
||||
|
||||
if ($userByOpenid && $userByPhone && (int) $userByOpenid['id'] !== (int) $userByPhone['id']) {
|
||||
$b = $userByPhone;
|
||||
$a = $userByOpenid;
|
||||
$bOpenid = trim((string) ($b['openid'] ?? ''));
|
||||
if ($bOpenid !== '') {
|
||||
return error('该手机号已绑定其他微信号,请使用原微信打开', 409);
|
||||
}
|
||||
$orphanOpenid = 'orphan_' . $a['id'] . '_' . $now;
|
||||
if (strlen($orphanOpenid) > 64) {
|
||||
$orphanOpenid = substr($orphanOpenid, 0, 64);
|
||||
}
|
||||
Db::name('wechat_users')->where('id', $a['id'])->update([
|
||||
'openid' => $orphanOpenid,
|
||||
'updatedAt' => $now,
|
||||
]);
|
||||
$mergeUpdate = [
|
||||
'openid' => $openid,
|
||||
'unionid' => $unionid,
|
||||
'sessionKey' => $sessionKey,
|
||||
'lastLoginAt' => $now,
|
||||
'lastLoginIp' => $ip,
|
||||
'updatedAt' => $now,
|
||||
];
|
||||
$existingEidB = $b['enterpriseId'] ?? null;
|
||||
if (($existingEidB === null || $existingEidB === '' || (int) $existingEidB === 0) && $loginEnterpriseId !== null) {
|
||||
$mergeUpdate['enterpriseId'] = $loginEnterpriseId;
|
||||
}
|
||||
Db::name('wechat_users')->where('id', $b['id'])->update($mergeUpdate);
|
||||
ThirdPartyChannelService::applyToUserId((int) $b['id'], $thirdParty);
|
||||
$wechatUser = Db::name('wechat_users')->where('id', $b['id'])->find();
|
||||
} elseif (!$userByOpenid && $userByPhone) {
|
||||
$b = $userByPhone;
|
||||
$bOpenid = trim((string) ($b['openid'] ?? ''));
|
||||
if ($bOpenid !== '') {
|
||||
return error('该手机号已绑定其他微信号,请使用原微信打开', 409);
|
||||
}
|
||||
$mergeUpdate = [
|
||||
'openid' => $openid,
|
||||
'unionid' => $unionid,
|
||||
'sessionKey' => $sessionKey,
|
||||
'lastLoginAt' => $now,
|
||||
'lastLoginIp' => $ip,
|
||||
'updatedAt' => $now,
|
||||
];
|
||||
$existingEidB = $b['enterpriseId'] ?? null;
|
||||
if (($existingEidB === null || $existingEidB === '' || (int) $existingEidB === 0) && $loginEnterpriseId !== null) {
|
||||
$mergeUpdate['enterpriseId'] = $loginEnterpriseId;
|
||||
}
|
||||
Db::name('wechat_users')->where('id', $b['id'])->update($mergeUpdate);
|
||||
ThirdPartyChannelService::applyToUserId((int) $b['id'], $thirdParty);
|
||||
$wechatUser = Db::name('wechat_users')->where('id', $b['id'])->find();
|
||||
} elseif ($userByOpenid) {
|
||||
$wechatUser = $userByOpenid;
|
||||
$updateFields = [
|
||||
'sessionKey' => $sessionKey,
|
||||
'unionid' => $unionid,
|
||||
@@ -242,12 +312,12 @@ class Auth extends BaseController
|
||||
'lastLoginIp' => $ip,
|
||||
'updatedAt' => $now,
|
||||
];
|
||||
// 老用户未绑定企业时,从本次登录上下文补写
|
||||
$existingEid = $wechatUser['enterpriseId'] ?? null;
|
||||
if (($existingEid === null || $existingEid === '' || (int) $existingEid === 0) && $loginEnterpriseId !== null) {
|
||||
$updateFields['enterpriseId'] = $loginEnterpriseId;
|
||||
}
|
||||
Db::name('wechat_users')->where('id', $wechatUser['id'])->update($updateFields);
|
||||
ThirdPartyChannelService::applyToUserId((int) $wechatUser['id'], $thirdParty);
|
||||
$wechatUser = Db::name('wechat_users')->where('id', $wechatUser['id'])->find();
|
||||
} else {
|
||||
$insertData = [
|
||||
@@ -255,26 +325,28 @@ class Auth extends BaseController
|
||||
'unionid' => $unionid,
|
||||
'sessionKey' => $sessionKey,
|
||||
'nickname' => null,
|
||||
'avatar' => null,
|
||||
'phone' => null,
|
||||
'gender' => 0,
|
||||
'country' => null,
|
||||
'province' => null,
|
||||
'city' => null,
|
||||
'status' => 1,
|
||||
'avatar' => null,
|
||||
'phone' => null,
|
||||
'gender' => 0,
|
||||
'country' => null,
|
||||
'province' => null,
|
||||
'city' => null,
|
||||
'status' => 1,
|
||||
'lastLoginAt' => $now,
|
||||
'lastLoginIp' => $ip,
|
||||
'createdAt' => $now,
|
||||
'updatedAt' => $now,
|
||||
'createdAt' => $now,
|
||||
'updatedAt' => $now,
|
||||
];
|
||||
if ($loginEnterpriseId !== null) {
|
||||
$insertData['enterpriseId'] = $loginEnterpriseId;
|
||||
}
|
||||
$id = Db::name('wechat_users')->insertGetId($insertData);
|
||||
$id = Db::name('wechat_users')->insertGetId($insertData);
|
||||
$wechatUser = Db::name('wechat_users')->where('id', $id)->find();
|
||||
ThirdPartyChannelService::applyToUserId((int) $id, $thirdParty);
|
||||
$wechatUser = Db::name('wechat_users')->where('id', $id)->find();
|
||||
}
|
||||
|
||||
if (($wechatUser['status'] ?? 1) != 1) {
|
||||
if (!$wechatUser || ($wechatUser['status'] ?? 1) != 1) {
|
||||
return error('账号已被禁用', 403);
|
||||
}
|
||||
|
||||
@@ -285,7 +357,6 @@ class Auth extends BaseController
|
||||
$token = JwtService::generateToken($payload);
|
||||
|
||||
$userId = (int) $wechatUser['id'];
|
||||
// 企业绑定取自 wechat_users.enterpriseId(企业分享测试链接时更新,个人分享不更新)
|
||||
$enterpriseId = isset($wechatUser['enterpriseId']) && $wechatUser['enterpriseId'] !== '' && $wechatUser['enterpriseId'] !== null
|
||||
? (int) $wechatUser['enterpriseId']
|
||||
: null;
|
||||
|
||||
@@ -694,6 +694,15 @@ class Test extends BaseController
|
||||
} catch (\Throwable $e) {
|
||||
// 上报失败不阻断
|
||||
}
|
||||
|
||||
// 第三方开放平台:ext_uid 或 third_party_phone 有值且配置 URL/Key 时推送(含人脸走 mbti 字段)
|
||||
try {
|
||||
if (is_array($result)) {
|
||||
\app\common\service\OpenPlatformService::notifyQuestionnaireIfNeeded($userId, $testType, $result);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 对接失败不阻断
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return error('保存测试结果失败', 500);
|
||||
@@ -1021,5 +1030,6 @@ class Test extends BaseController
|
||||
'usingSuperAdminBank' => $resolvedEnterpriseId === null,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,10 @@ class WechatUser extends Model
|
||||
'sessionKey' => 'string',
|
||||
'nickname' => 'string',
|
||||
'avatar' => 'string',
|
||||
'phone' => 'string',
|
||||
'phone' => 'string',
|
||||
'ext_uid' => 'string',
|
||||
'third_party_phone' => 'string',
|
||||
'third_party_tid' => 'string',
|
||||
'gender' => 'int',
|
||||
'country' => 'string',
|
||||
'province' => 'string',
|
||||
|
||||
Reference in New Issue
Block a user