Files
cunkebao_v3/Server/script/migration/migrate_company_attribution.php
Manus AI 5517457929 sync: 以本地为准同步全量变更至 GitHub
含四端需求文档、前端/后端/超管/触客宝迭代及部署脚本更新;未拉取远程。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 04:24:56 +08:00

135 lines
4.6 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* 存客宝数据迁移 · 公司归属修复脚本DRY-RUN 优先)
*
* 用途:把指定手机号 / 旧 companyId 下的计划、客资、积分、海报/渠道获客记录
* 迁移到目标 companyId卡若指定。默认 DRY-RUN只输出 SQL不执行。
*
* 用法:
* # 仅打印影响行数与映射,不执行
* docker compose exec -T server php /var/www/html/script/migration/migrate_company_attribution.php \
* sourcePhone=13779954946 fromCompany=15880802661 toCompany=914
*
* # 加 --apply 后真正执行(卡若手动确认后再加)
* docker compose exec -T server php /var/www/html/script/migration/migrate_company_attribution.php \
* sourcePhone=13779954946 fromCompany=15880802661 toCompany=914 apply=1
*
* 卡若 2026-05-27 · 数据迁移 D1/D2 公司归属修复
*/
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);
}
}
$sourcePhone = $args['sourcePhone'] ?? '';
$fromCompany = (int)($args['fromCompany'] ?? 0);
$toCompany = (int)($args['toCompany'] ?? 0);
$apply = !empty($args['apply']);
if (!$sourcePhone || !$fromCompany || !$toCompany) {
fwrite(STDERR, "usage: sourcePhone=1XXX fromCompany=X toCompany=Y [apply=1]\n");
exit(1);
}
$mode = $apply ? '【APPLY 实际执行】' : '【DRY-RUN 不执行】';
echo "$mode source phone=$sourcePhone, from companyId=$fromCompany → to companyId=$toCompany\n";
// 步骤 1定位待迁移对象
$users = Db::name('users')
->where('companyId', $fromCompany)
->where(function ($q) use ($sourcePhone) {
$q->where('phone', $sourcePhone)->whereOr('account', $sourcePhone);
})
->select();
if (!$users) {
echo "未找到符合条件的用户,退出。\n";
exit(0);
}
$userIds = array_column((array)$users, 'id');
echo "影响用户:" . count($userIds) . " 个 (ids=" . implode(',', $userIds) . ")\n";
$tables = [
// [表名, 字段, 描述]
['customer_acquisition_task', 'companyId', '获客计划(含海报/渠道/付款码等场景)'],
['tokens_company', 'companyId', '算力账户'],
['plan_distribution_channel', 'companyId', '渠道获客分销渠道'],
['plan_distribution_record', 'companyId', '渠道分销记录'],
['ckb_lead_records', 'companyId', '客资入池队列'],
['content_library', 'companyId', '内容库'],
['workbench_moments_sync', 'companyId', '工作台 · 朋友圈同步'],
['workbench_group_push', 'companyId', '工作台 · 群消息推送'],
['workbench_auto_like', 'companyId', '工作台 · 自动点赞'],
];
$plan = [];
$totalAffected = 0;
Db::startTrans();
try {
foreach ($tables as [$table, $field, $desc]) {
$exists = Db::query("SHOW TABLES LIKE '" . Db::name($table)->getTable() . "'");
if (!$exists) {
echo " · [SKIP] 表 $table 不存在\n";
continue;
}
$count = Db::name($table)->where($field, $fromCompany)->count();
echo " · $table ($desc): 待迁移 $count";
if ($apply && $count > 0) {
$affected = Db::name($table)
->where($field, $fromCompany)
->update([$field => $toCompany]);
$totalAffected += $affected;
echo " → 已迁移 $affected\n";
} else {
echo "\n";
}
$plan[$table] = $count;
}
if ($apply) {
Db::commit();
echo "\n✅ 迁移完成,共影响 $totalAffected\n";
} else {
Db::rollback();
echo "\n[DRY-RUN] 共可迁移 " . array_sum($plan) . " 行(未执行)。如确认无误,请追加 apply=1 重跑。\n";
}
} catch (\Throwable $e) {
Db::rollback();
fwrite(STDERR, "失败回滚:" . $e->getMessage() . "\n");
exit(2);
}
// 输出迁移报告
$reportDir = dirname(__DIR__, 2) . '/runtime/migration/' . $sourcePhone;
if (!is_dir($reportDir)) {
@mkdir($reportDir, 0755, true);
}
$reportPath = $reportDir . '/migrate-' . ($apply ? 'apply' : 'dryrun') . '-' . date('YmdHis') . '.json';
file_put_contents($reportPath, json_encode([
'sourcePhone' => $sourcePhone,
'fromCompany' => $fromCompany,
'toCompany' => $toCompany,
'mode' => $apply ? 'apply' : 'dry-run',
'userIds' => $userIds,
'plan' => $plan,
'totalAffected' => $totalAffected,
'finishedAt' => date('c'),
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
echo "report: $reportPath\n";