155 lines
4.9 KiB
PHP
155 lines
4.9 KiB
PHP
<?php
|
||
/**
|
||
* 存客宝 · 单用户公司归属修复(按手机号迁移到目标 companyId)
|
||
*
|
||
* 用途:13779954946 应从卡若(914)迁到黑科技/老坑爹/魔兽(2130);15880802661 保持 914。
|
||
* 只迁移该 userId 名下的计划、内容库、算力账户,不影响同公司其他用户。
|
||
*
|
||
* 用法:
|
||
* docker compose exec -T server php /var/www/html/script/migration/fix_user_company.php \
|
||
* phone=13779954946 toCompany=2130
|
||
*
|
||
* docker compose exec -T server php /var/www/html/script/migration/fix_user_company.php \
|
||
* phone=13779954946 toCompany=2130 apply=1
|
||
*/
|
||
|
||
declare(strict_types=1);
|
||
|
||
require __DIR__ . '/../../thinkphp/base.php';
|
||
|
||
use think\Db;
|
||
use think\App;
|
||
|
||
$app = new App(realpath(__DIR__ . '/../../application'));
|
||
$app->initialize();
|
||
|
||
$args = [];
|
||
foreach ($argv as $arg) {
|
||
if (strpos($arg, '=') !== false) {
|
||
list($k, $v) = explode('=', $arg, 2);
|
||
$args[trim($k)] = trim($v);
|
||
}
|
||
}
|
||
|
||
$phone = $args['phone'] ?? '';
|
||
$toCompany = (int)($args['toCompany'] ?? 0);
|
||
$apply = !empty($args['apply']);
|
||
|
||
if (!$phone || !$toCompany) {
|
||
fwrite(STDERR, "usage: phone=1XXXXXXXXXX toCompany=2130 [apply=1]\n");
|
||
exit(1);
|
||
}
|
||
|
||
$user = Db::name('users')
|
||
->where('phone', $phone)
|
||
->whereOr('account', $phone)
|
||
->find();
|
||
|
||
if (!$user) {
|
||
fwrite(STDERR, "未找到手机号 {$phone} 对应用户\n");
|
||
exit(1);
|
||
}
|
||
|
||
$userId = (int)$user['id'];
|
||
$fromCompany = (int)$user['companyId'];
|
||
|
||
if ($fromCompany === $toCompany) {
|
||
echo "用户 {$phone} (id={$userId}) 已在 companyId={$toCompany},无需迁移。\n";
|
||
exit(0);
|
||
}
|
||
|
||
$mode = $apply ? '【APPLY】' : '【DRY-RUN】';
|
||
echo "{$mode} phone={$phone} userId={$userId} username={$user['username']} "
|
||
. "companyId {$fromCompany} → {$toCompany}\n";
|
||
|
||
$fromName = Db::name('company')->where('id', $fromCompany)->value('name') ?: '?';
|
||
$toName = Db::name('company')->where('id', $toCompany)->value('name') ?: '?';
|
||
echo " 源公司: {$fromName} ({$fromCompany})\n";
|
||
echo " 目标公司: {$toName} ({$toCompany})\n";
|
||
|
||
$plan = [];
|
||
Db::startTrans();
|
||
try {
|
||
// 1) 用户主表
|
||
$plan['users'] = 1;
|
||
echo " · ck_users: 1 行\n";
|
||
if ($apply) {
|
||
Db::name('users')->where('id', $userId)->update([
|
||
'companyId' => $toCompany,
|
||
'updateTime' => time(),
|
||
]);
|
||
}
|
||
|
||
// 2) 按 userId 迁移的业务表
|
||
$userScoped = [
|
||
['customer_acquisition_task', 'userId', 'companyId', '获客计划'],
|
||
['content_library', 'userId', 'companyId', '内容库'],
|
||
['tokens_company', 'userId', 'companyId', '算力账户'],
|
||
];
|
||
|
||
foreach ($userScoped as [$table, $userField, $companyField, $desc]) {
|
||
try {
|
||
$count = (int)Db::name($table)
|
||
->where($userField, $userId)
|
||
->where($companyField, $fromCompany)
|
||
->count();
|
||
$plan[$table] = $count;
|
||
echo " · {$table} ({$desc}): {$count} 行\n";
|
||
if ($apply && $count > 0) {
|
||
Db::name($table)
|
||
->where($userField, $userId)
|
||
->where($companyField, $fromCompany)
|
||
->update([$companyField => $toCompany]);
|
||
}
|
||
} catch (\Throwable $e) {
|
||
echo " · [SKIP] {$table}: {$e->getMessage()}\n";
|
||
}
|
||
}
|
||
|
||
// 3) 该用户名下、仍挂在旧公司的内容库素材(libraryId 归属已迁则自动正确)
|
||
try {
|
||
$libIds = Db::name('content_library')->where('userId', $userId)->column('id');
|
||
if ($libIds) {
|
||
// 无 companyId 字段,仅统计
|
||
$itemCount = (int)Db::name('content_item')
|
||
->whereIn('libraryId', $libIds)
|
||
->where('isDel', 0)
|
||
->count();
|
||
$plan['content_item'] = $itemCount;
|
||
echo " · content_item (素材,随内容库): {$itemCount} 行\n";
|
||
}
|
||
} catch (\Throwable $e) {
|
||
echo " · [SKIP] content_item: {$e->getMessage()}\n";
|
||
}
|
||
|
||
if ($apply) {
|
||
Db::commit();
|
||
echo "\n✅ 迁移完成\n";
|
||
} else {
|
||
Db::rollback();
|
||
echo "\n[DRY-RUN] 未写入。确认后加 apply=1 重跑。\n";
|
||
}
|
||
} catch (\Throwable $e) {
|
||
Db::rollback();
|
||
fwrite(STDERR, "失败回滚:{$e->getMessage()}\n");
|
||
exit(2);
|
||
}
|
||
|
||
$reportDir = dirname(__DIR__, 2) . '/runtime/migration/' . $phone;
|
||
if (!is_dir($reportDir)) {
|
||
@mkdir($reportDir, 0755, true);
|
||
}
|
||
$reportPath = $reportDir . '/fix-user-company-' . ($apply ? 'apply' : 'dryrun') . '-' . date('YmdHis') . '.json';
|
||
file_put_contents($reportPath, json_encode([
|
||
'phone' => $phone,
|
||
'userId' => $userId,
|
||
'fromCompany' => $fromCompany,
|
||
'toCompany' => $toCompany,
|
||
'fromName' => $fromName,
|
||
'toName' => $toName,
|
||
'mode' => $apply ? 'apply' : 'dry-run',
|
||
'plan' => $plan,
|
||
'finishedAt' => date('c'),
|
||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||
echo "report: {$reportPath}\n";
|