From 23826cd06e18dcd5035c47b9aeedb39456fa719e Mon Sep 17 00:00:00 2001 From: augushong Date: Fri, 9 Jan 2026 22:26:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor(scheme):=20=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=87=E4=BB=BD=E8=A1=A8=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/scheme/MallGoods.php | 4 +- extend/base/common/command/scheme/Sync.php | 77 +++++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/app/admin/scheme/MallGoods.php b/app/admin/scheme/MallGoods.php index b21ab9a..8fdf352 100644 --- a/app/admin/scheme/MallGoods.php +++ b/app/admin/scheme/MallGoods.php @@ -40,10 +40,10 @@ class MallGoods extends BaseScheme #[Field(type: 'text', comment: '商品属性')] public $property; - #[Field(type: 'decimal', length: 8, precision: 8, scale: 2, default: '0.00', comment: '市场价')] + #[Field(type: 'decimal', length: 8, precision: 8, default: '0', comment: '市场价')] public $market_price; - #[Field(type: 'decimal', length: 8, precision: 8, scale: 2, default: '0.00', comment: '折扣价')] + #[Field(type: 'decimal', length: 8, precision: 8, default: '0', comment: '折扣价')] public $discount_price; #[Field(type: 'int', length: 11, default: '0', comment: '销量', unsigned: true)] diff --git a/extend/base/common/command/scheme/Sync.php b/extend/base/common/command/scheme/Sync.php index bb91533..ea544ac 100644 --- a/extend/base/common/command/scheme/Sync.php +++ b/extend/base/common/command/scheme/Sync.php @@ -7,7 +7,9 @@ use think\console\Input; use think\console\input\Option; use think\console\Output; use think\facade\Config; +use think\facade\Db; use app\common\service\scheme\SchemeToDbService; +use app\common\service\scheme\DbToSchemeService; use app\common\scheme\attribute\Table; use ReflectionClass; @@ -26,10 +28,12 @@ class Sync extends Command $skipData = $input->getOption('skip-data'); $service = new SchemeToDbService(); + $generator = new DbToSchemeService(); $schemeDir = app()->getAppPath() . 'admin/scheme/'; $ignoreTables = Config::get('scheme.ignore_tables', []); $connection = Config::get('database.default', 'mysql'); $prefix = Config::get('database.connections.' . $connection . '.prefix', ''); + $backupPrefix = Config::get('scheme.backup_prefix', 'backup'); if (!is_dir($schemeDir)) { $output->writeln("Scheme directory not found: $schemeDir"); @@ -43,11 +47,37 @@ class Sync extends Command if (class_exists($className)) { $tableName = $this->getTableNameFromScheme($className); - if (!empty($tableName) && $this->isIgnoredTable($tableName, $ignoreTables, $prefix)) { - $output->writeln("Skipping $className (ignored table: $tableName)"); + if (empty($tableName)) { + $output->writeln("Skipping $className (missing table name)"); continue; } + $fullTableName = $this->getFullTableName($tableName, $prefix); + if ($this->isBackupTable($fullTableName, $prefix, $backupPrefix)) { + $output->writeln("Skipping $className (backup table: $fullTableName)"); + continue; + } + + if ($this->isIgnoredTable($fullTableName, $ignoreTables, $prefix)) { + $output->writeln("Skipping $className (ignored table: $fullTableName)"); + continue; + } + + if ($this->checkTableExists($connection, $fullTableName)) { + try { + $expectedClass = basename($file, '.php'); + $generated = $generator->generate($fullTableName, $expectedClass); + $existing = (string)file_get_contents($file); + if ($this->normalizeCode($generated) === $this->normalizeCode($existing)) { + $output->writeln("Skipping $className (no schema changes)"); + continue; + } + } catch (\Exception $e) { + $output->writeln("Check failed for $className: " . $e->getMessage() . ""); + continue; + } + } + $output->writeln("Syncing $className..."); try { $backup = $service->sync($className, $skipData); @@ -91,4 +121,47 @@ class Sync extends Command return in_array($shortName, $ignoreTables, true) || in_array($tableName, $ignoreTables, true); } + + protected function normalizeCode(string $code): string + { + $code = str_replace(["\r\n", "\r"], "\n", $code); + $code = preg_replace('/[ \t]+$/m', '', $code); + return trim((string)$code); + } + + protected function checkTableExists(string $connection, string $tableName): bool + { + $database = (string)Config::get('database.connections.' . $connection . '.database', ''); + if ($database !== '') { + $rows = Db::connect($connection)->query( + 'SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? LIMIT 1', + [$database, $tableName] + ); + return !empty($rows); + } + + $escaped = addcslashes($tableName, "\\_%"); + $tables = Db::connect($connection)->query("SHOW TABLES LIKE '$escaped'"); + return !empty($tables); + } + + protected function getFullTableName(string $tableName, string $prefix): string + { + if ($prefix && !str_starts_with($tableName, $prefix)) { + return $prefix . $tableName; + } + + return $tableName; + } + + protected function isBackupTable(string $tableName, string $prefix, string $backupPrefix): bool + { + $basePrefix = $prefix . $backupPrefix; + if ($basePrefix === '') { + return false; + } + + $pattern = '/^' . preg_quote($basePrefix, '/') . '_?\\d{14}(?:_.*)?$/'; + return preg_match($pattern, $tableName) === 1; + } }