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;
+ }
}