192 lines
6.5 KiB
PHP
192 lines
6.5 KiB
PHP
<?php
|
||
/**
|
||
* 一键执行渠道与游戏配置初始化(需已备份数据库)
|
||
* 用法:在 server 目录执行 php db/run_all_init.php
|
||
*/
|
||
declare(strict_types=1);
|
||
|
||
define('BASE_PATH', dirname(__DIR__));
|
||
|
||
require_once BASE_PATH . '/vendor/autoload.php';
|
||
|
||
if (class_exists(\Dotenv\Dotenv::class) && is_file(BASE_PATH . '/.env')) {
|
||
if (method_exists(\Dotenv\Dotenv::class, 'createUnsafeMutable')) {
|
||
\Dotenv\Dotenv::createUnsafeMutable(BASE_PATH)->load();
|
||
} else {
|
||
\Dotenv\Dotenv::createMutable(BASE_PATH)->load();
|
||
}
|
||
}
|
||
|
||
// 加载配置(排除 route.php,避免 CLI 报错)
|
||
\Webman\Config::load(BASE_PATH . '/config', ['route', 'plugin']);
|
||
\Webman\ThinkOrm\ThinkOrm::start(null);
|
||
|
||
use app\dice\service\DiceChannelConfigService;
|
||
use plugin\saiadmin\app\model\system\SystemDept;
|
||
use plugin\saiadmin\app\model\system\SystemUser;
|
||
use support\think\Db;
|
||
|
||
function cliPdo(): PDO
|
||
{
|
||
$host = getenv('DB_HOST') ?: '127.0.0.1';
|
||
$port = getenv('DB_PORT') ?: '3306';
|
||
$db = getenv('DB_NAME') ?: '';
|
||
$user = getenv('DB_USER') ?: '';
|
||
$pass = getenv('DB_PASSWORD') ?: '';
|
||
$dsn = "mysql:host={$host};port={$port};dbname={$db};charset=utf8mb4";
|
||
return new PDO($dsn, $user, $pass, [
|
||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||
]);
|
||
}
|
||
|
||
function runSqlFile(PDO $pdo, string $path, string $label, bool $alterOnly = false): void
|
||
{
|
||
echo "\n=== {$label} ===\n";
|
||
if (!is_file($path)) {
|
||
echo "跳过:文件不存在\n";
|
||
return;
|
||
}
|
||
$sql = file_get_contents($path);
|
||
$sql = preg_replace('/--.*$/m', '', $sql);
|
||
$parts = array_filter(array_map('trim', explode(';', $sql)));
|
||
$ok = 0;
|
||
$skip = 0;
|
||
foreach ($parts as $statement) {
|
||
if ($statement === '') {
|
||
continue;
|
||
}
|
||
if ($alterOnly && stripos($statement, 'ALTER TABLE') !== 0) {
|
||
continue;
|
||
}
|
||
try {
|
||
$pdo->exec($statement);
|
||
$ok++;
|
||
} catch (PDOException $e) {
|
||
$msg = $e->getMessage();
|
||
$isAlter = stripos($statement, 'ALTER TABLE') === 0;
|
||
if ($isAlter && (stripos($msg, 'Duplicate column') !== false
|
||
|| stripos($msg, 'Duplicate key name') !== false)) {
|
||
$skip++;
|
||
} elseif (!$isAlter) {
|
||
echo " [警告] " . substr($msg, 0, 120) . "\n";
|
||
$skip++;
|
||
} else {
|
||
echo " [错误] {$msg}\n";
|
||
throw $e;
|
||
}
|
||
}
|
||
}
|
||
echo "完成:成功 {$ok} 条" . ($skip > 0 ? ",跳过 {$skip} 条(字段已存在)" : '') . "\n";
|
||
}
|
||
|
||
function getRootDeptId(int $deptId): ?int
|
||
{
|
||
$currentId = $deptId;
|
||
$visited = [];
|
||
while ($currentId > 0 && !isset($visited[$currentId])) {
|
||
$visited[$currentId] = true;
|
||
$dept = SystemDept::find($currentId);
|
||
if (!$dept) {
|
||
return null;
|
||
}
|
||
$parentId = (int) ($dept->parent_id ?? 0);
|
||
if ($parentId === 0) {
|
||
return $currentId;
|
||
}
|
||
$currentId = $parentId;
|
||
}
|
||
return $currentId > 0 ? $currentId : null;
|
||
}
|
||
|
||
echo "========== 大富翁渠道/配置初始化 ==========\n";
|
||
echo '数据库: ' . (getenv('DB_NAME') ?: '') . '@' . (getenv('DB_HOST') ?: '') . "\n";
|
||
|
||
$pdo = cliPdo();
|
||
|
||
runSqlFile($pdo, __DIR__ . '/dice_tables_add_dept_id.sql', '1. dice 表增加 dept_id', true);
|
||
runSqlFile($pdo, __DIR__ . '/dept_flatten_channels.sql', '2. 渠道扁平化 SQL');
|
||
|
||
echo "\n=== 3. 渠道扁平化 PHP(多级用户归并 + 删除子渠道) ===\n";
|
||
Db::transaction(function () {
|
||
$users = SystemUser::where('dept_id', '>', 0)->select();
|
||
$moved = 0;
|
||
foreach ($users as $user) {
|
||
$deptId = (int) $user->dept_id;
|
||
$rootId = getRootDeptId($deptId);
|
||
if ($rootId !== null && $rootId !== $deptId) {
|
||
SystemUser::where('id', $user->id)->update(['dept_id' => $rootId]);
|
||
echo " 用户 {$user->id}: dept {$deptId} -> {$rootId}\n";
|
||
$moved++;
|
||
}
|
||
}
|
||
$childIds = SystemDept::where('parent_id', '>', 0)->column('id');
|
||
if (!empty($childIds)) {
|
||
SystemDept::destroy($childIds);
|
||
echo ' 已删除子渠道: ' . implode(',', $childIds) . "\n";
|
||
} else {
|
||
echo " 无子渠道需删除\n";
|
||
}
|
||
SystemDept::where('id', '>', 0)->update(['parent_id' => 0, 'level' => '0']);
|
||
echo " 用户归并 {$moved} 人,渠道扁平化完成\n";
|
||
});
|
||
|
||
$service = new DiceChannelConfigService();
|
||
|
||
echo "\n=== 3.5 配置表复合键与默认模板 dept_id=0 ===\n";
|
||
$service->ensureConfigCompositeKeys();
|
||
echo " dice_config / dice_reward_config: ok\n";
|
||
|
||
echo "\n=== 3.6 彩金池配置按渠道唯一(dept_id + name) ===\n";
|
||
try {
|
||
$indexes = Db::query("SHOW INDEX FROM `dice_lottery_pool_config` WHERE Key_name = 'dice_lottery_poll_config_unique'");
|
||
if (!empty($indexes)) {
|
||
Db::execute('ALTER TABLE `dice_lottery_pool_config` DROP INDEX `dice_lottery_poll_config_unique`');
|
||
echo " 已移除 name 全局唯一索引\n";
|
||
}
|
||
$uk = Db::query("SHOW INDEX FROM `dice_lottery_pool_config` WHERE Key_name = 'uk_dept_name'");
|
||
if (empty($uk)) {
|
||
Db::execute('ALTER TABLE `dice_lottery_pool_config` ADD UNIQUE KEY `uk_dept_name` (`dept_id`, `name`)');
|
||
echo " 已添加 uk_dept_name(dept_id, name)\n";
|
||
} else {
|
||
echo " uk_dept_name 已存在\n";
|
||
}
|
||
} catch (\Throwable $e) {
|
||
echo " 跳过: {$e->getMessage()}\n";
|
||
}
|
||
|
||
echo "\n=== 4. 将现有配置设为默认模板(dept_id=0) ===\n";
|
||
$tables = [
|
||
'dice_config',
|
||
'dice_ante_config',
|
||
'dice_lottery_pool_config',
|
||
'dice_reward_config',
|
||
'dice_reward',
|
||
'dice_game',
|
||
];
|
||
foreach ($tables as $table) {
|
||
try {
|
||
Db::table($table)->update(['dept_id' => 0]);
|
||
echo " {$table}: ok\n";
|
||
} catch (\Throwable $e) {
|
||
echo " {$table}: 跳过 ({$e->getMessage()})\n";
|
||
}
|
||
}
|
||
|
||
echo "\n=== 5. 为所有渠道从默认模板复制配置 ===\n";
|
||
$summary = $service->syncAllChannelsFromDefault();
|
||
foreach ($summary as $deptId => $info) {
|
||
$copied = implode(',', $info['copied'] ?? []) ?: '无';
|
||
$skipped = implode(',', $info['skipped'] ?? []) ?: '无';
|
||
echo " 渠道 {$deptId}: 复制 [{$copied}],跳过 [{$skipped}]\n";
|
||
}
|
||
|
||
echo "\n=== 6. 修复无效渠道并回填 dept_id ===\n";
|
||
echo " 无效渠道归并: ";
|
||
print_r($service->repairOrphanDeptReferences());
|
||
echo " 回填: ";
|
||
print_r($service->backfillDataDeptId());
|
||
|
||
$deptCount = SystemDept::count();
|
||
echo "\n当前顶级渠道数: {$deptCount}\n";
|
||
echo "========== 全部初始化完成 ==========\n";
|