DB数据库文件

This commit is contained in:
2026-05-26 09:43:42 +08:00
parent e0b303c5d4
commit a4c8f623be
30 changed files with 1416 additions and 0 deletions

191
server/db/run_all_init.php Normal file
View File

@@ -0,0 +1,191 @@
<?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";