高考版优化

审核模式优化
This commit is contained in:
Ghost
2026-04-29 18:01:26 +08:00
parent 59419c4ce9
commit a411bf7b21
134 changed files with 19898 additions and 3371 deletions

View File

@@ -348,6 +348,63 @@ class DataMigration extends BaseController
Db::name('user_profile')->insert($base);
}
/**
* 归属目标企业且仍存在 personal(NULL) 画像行的用户,逐批合并(避免一次载入全部 userId / 超长事务)。
*
* @return int 实际调用合并逻辑的用户数
*/
private function mergePersonalProfilesForEnterpriseInBatches(int $targetEnterpriseId, int $now, int $batchSize = 400): int
{
if ($targetEnterpriseId <= 0) {
return 0;
}
$tUp = Db::name('user_profile')->getTable();
$tWu = Db::name('wechat_users')->getTable();
$batchSize = max(50, min($batchSize, 2000));
$lastUid = 0;
$merged = 0;
while (true) {
$sql = 'SELECT DISTINCT `up`.`userId` AS `uid` FROM `' . $tUp . '` `up` '
. 'INNER JOIN `' . $tWu . '` `w` ON `w`.`id` = `up`.`userId` '
. 'WHERE `up`.`userType` = \'personal\' '
. 'AND (`up`.`enterpriseId` IS NULL OR `up`.`enterpriseId` = 0) '
. 'AND `w`.`enterpriseId` = ? '
. 'AND `up`.`userId` > ? '
. 'ORDER BY `up`.`userId` ASC '
. 'LIMIT ' . $batchSize;
$rows = Db::query($sql, [$targetEnterpriseId, $lastUid]);
if ($rows === null || $rows === [] || !is_array($rows)) {
break;
}
$uids = [];
foreach ($rows as $row) {
$uid = (int) ($row['uid'] ?? 0);
if ($uid > 0) {
$uids[] = $uid;
}
}
if ($uids === []) {
break;
}
foreach ($uids as $uid) {
$this->mergePersonalUserProfileIntoEnterprise($uid, $targetEnterpriseId, $now);
$merged++;
}
$lastUid = max($uids);
if (count($rows) < $batchSize) {
break;
}
}
return $merged;
}
/**
* 存客宝归并wechat_users 无企业用户写入目标企业;
* 已/将归属该企业的用户下test_results 中 enterpriseId 为空的记录补写目标企业;
@@ -386,27 +443,25 @@ class DataMigration extends BaseController
return error('目标企业不存在', 404);
}
$orphanUserIds = Db::name('wechat_users')
$eid = $targetEnterpriseId;
$wechatAffected = (int) Db::name('wechat_users')
->whereRaw($this->sqlWechatUserUnassignedEnterprise())
->column('id');
$orphanUserIds = array_values(array_unique(array_filter(array_map('intval', $orphanUserIds))));
$wechatAffected = count($orphanUserIds);
$boundNow = Db::name('wechat_users')
->where('enterpriseId', $targetEnterpriseId)
->column('id');
$boundNow = array_values(array_unique(array_filter(array_map('intval', $boundNow))));
$usersInScope = array_values(array_unique(array_merge($boundNow, $orphanUserIds)));
$testResultsAffected = empty($usersInScope) ? 0 : (int) Db::name('test_results')
->whereIn('userId', $usersInScope)
->whereRaw($this->sqlTestResultUnassignedEnterprise())
->count();
$userProfilePersonalRows = empty($usersInScope) ? 0 : (int) Db::name('user_profile')
->where('userType', 'personal')
->whereRaw('(`enterpriseId` IS NULL OR `enterpriseId` = 0)')
->whereIn('userId', $usersInScope)
$wechatScopeExpr = '((w.`enterpriseId` IS NULL OR w.`enterpriseId` = 0) OR w.`enterpriseId` = ' . $eid . ')';
$testResultsAffected = (int) Db::name('test_results')->alias('tr')
->join('wechat_users w', 'w.id = tr.userId')
->whereRaw('(tr.`enterpriseId` IS NULL OR tr.`enterpriseId` = 0)')
->whereRaw($wechatScopeExpr)
->count();
$userProfilePersonalRows = (int) Db::name('user_profile')->alias('up')
->join('wechat_users w', 'w.id = up.userId')
->where('up.userType', 'personal')
->whereRaw('(up.`enterpriseId` IS NULL OR up.`enterpriseId` = 0)')
->whereRaw($wechatScopeExpr)
->count();
$preview = [
@@ -434,47 +489,52 @@ class DataMigration extends BaseController
return success($preview, '无需归并');
}
if (function_exists('set_time_limit')) {
@set_time_limit(0);
}
@ignore_user_abort(true);
$now = time();
Db::startTrans();
try {
if (!empty($orphanUserIds)) {
Db::name('wechat_users')
->whereIn('id', $orphanUserIds)
->whereRaw($this->sqlWechatUserUnassignedEnterprise())
->update([
'enterpriseId' => $targetEnterpriseId,
'updatedAt' => $now,
]);
}
Db::name('wechat_users')
->whereRaw($this->sqlWechatUserUnassignedEnterprise())
->update([
'enterpriseId' => $targetEnterpriseId,
'updatedAt' => $now,
]);
$boundAfter = Db::name('wechat_users')
->where('enterpriseId', $targetEnterpriseId)
->column('id');
$boundAfter = array_values(array_unique(array_filter(array_map('intval', $boundAfter))));
if (!empty($boundAfter)) {
Db::name('test_results')
->whereIn('userId', $boundAfter)
->whereRaw($this->sqlTestResultUnassignedEnterprise())
->update([
'enterpriseId' => $targetEnterpriseId,
'testScope' => 'enterprise',
'updatedAt' => $now,
]);
foreach ($boundAfter as $uid) {
$this->mergePersonalUserProfileIntoEnterprise((int) $uid, $targetEnterpriseId, $now);
}
}
$trTable = Db::name('test_results')->getTable();
$wuTable = Db::name('wechat_users')->getTable();
Db::execute(
'UPDATE `' . $trTable . '` AS `tr` INNER JOIN `' . $wuTable . '` AS `w` ON `tr`.`userId` = `w`.`id` '
. 'SET `tr`.`enterpriseId` = ?, `tr`.`testScope` = \'enterprise\', `tr`.`updatedAt` = ? '
. 'WHERE `w`.`enterpriseId` = ? AND (`tr`.`enterpriseId` IS NULL OR `tr`.`enterpriseId` = 0)',
[$targetEnterpriseId, $now, $targetEnterpriseId]
);
Db::commit();
} catch (\Throwable $e) {
Db::rollback();
return error('归并失败:' . $e->getMessage(), 500);
return error('归并失败(用户/测试写入):' . $e->getMessage(), 500);
}
$preview['executed'] = true;
$preview['hint'] = '已写入:小程序用户归属、无企业测试记录、画像 personal 行合并已完成。';
try {
$mergedProfiles = $this->mergePersonalProfilesForEnterpriseInBatches($targetEnterpriseId, $now);
} catch (\Throwable $e) {
return error(
'用户与测试记录已写入,但画像合并失败(可重试本接口):' . $e->getMessage(),
500
);
}
$preview['executed'] = true;
$preview['profileMergeProcessed'] = $mergedProfiles;
$preview['hint'] = '已写入小程序用户归属、无企业测试记录已批量更新personal 画像已合并 '
. $mergedProfiles . ' 人次。';
return success($preview, '归并完成');
}
}