Ver Fonte

'表数据结构管理'

gorden há 1 ano atrás
pai
commit
8d92359ab1

+ 4 - 0
app/admin/controller/sys_manage/Field.php

@@ -52,6 +52,10 @@ class Field
         if (!$validate->scene('add')->check($request->post())) {
             return json_fail($validate->getError());
         }
+        // 验证字段重复
+        if (FieldService::checkFieldExist($request->post('field_table'), $request->post('field_column_key'))) {
+            return json_fail('字段已存在,请勿重复添加');
+        }
 
         return FieldService::addField($request->post());
     }

+ 244 - 2
app/admin/service/sys_manage/FieldService.php

@@ -2,7 +2,11 @@
 
 namespace app\admin\service\sys_manage;
 
+use app\common\Util;
+use app\model\MemberInfo;
 use app\model\SysField;
+use Illuminate\Database\Schema\Blueprint;
+use support\Db;
 
 class FieldService
 {
@@ -61,6 +65,7 @@ class FieldService
      */
     public static function addField($params)
     {
+        Db::beginTransaction();
         try {
             $data = [
                 'field_status' => $params['field_status'],
@@ -78,8 +83,31 @@ class FieldService
                 'field_extend_json' => !empty($params['field_extend_json']) ? $params['field_extend_json'] : '{}',
                 'field_addtimes' => time()
             ];
+            // 入库
             SysField::insert($data);
+
+            // 字段设置
+            $column = [
+                'type' => $params['field_column_datatype'],
+                'field' => $params['field_column_key'],
+                'primary_key' => false,
+                'nullable' => true,
+                'default' => $params['field_column_default'],
+                'auto_increment' => false,
+                'comment' => $params['field_name']
+            ];
+            $defaultLength = Util::fieldDefaultLength();
+            if (isset($defaultLength[$column['type']])) {
+                $column['length'] = $defaultLength[$column['type']];
+            }
+            // 写入字段
+            Util::schema()->table($params['field_table'], function (Blueprint $table) use ($column) {
+                self::createColumn($table, $column);
+            });
+            Db::commit();
         } catch (\Exception $e) {
+            Db::rollBack();
+            dd($e->getMessage());
             return json_fail('创建字段失败');
         }
 
@@ -97,7 +125,9 @@ class FieldService
      */
     public static function updateField($id, $params)
     {
+        Db::beginTransaction();
         try {
+            $field = SysField::where('field_id', $id)->first();
             $data = [
                 'field_category' => $params['field_category'],
                 'field_name' => $params['field_name'],
@@ -112,9 +142,40 @@ class FieldService
                 'field_remark' => $params['field_remark'],
                 'field_extend_json' => !empty($params['field_extend_json']) ? $params['field_extend_json'] : '{}'
             ];
-
+            // 更新
             SysField::where('field_id', $id)->update($data);
+
+            // 字段设置
+            $column = [
+                'type' => $params['field_column_datatype'],
+                'field' => $params['field_column_key'],
+                'old_field' => $field->field_column_key,
+                'primary_key' => false,
+                'nullable' => true,
+                'default' => $params['field_column_default'],
+                'auto_increment' => false,
+                'comment' => $params['field_name']
+            ];
+            // 设置字段长度
+            $defaultLength = Util::fieldDefaultLength();
+            if (isset($defaultLength[$column['type']])) {
+                $column['length'] = $defaultLength[$column['type']];
+            }
+            // 表变动
+            if ($field->field_table != $params['field_table']) {
+                // 删原表字段
+                Util::db()->statement("ALTER TABLE " . getenv('DB_PREFIX') . $field->field_table . " DROP COLUMN `$field->field_column_key`");
+                // 在新表创建
+                Util::schema()->table($params['field_table'], function (Blueprint $table) use ($column) {
+                    self::createColumn($table, $column);
+                });
+            } else {
+                // 表没变,改就行
+                self::modifyColumn(getenv('DB_PREFIX') . $params['field_table'], $column);
+            }
+            Db::commit();
         } catch (\Exception $e) {
+            Db::rollBack();
             return json_fail('修改字段失败');
         }
 
@@ -151,12 +212,193 @@ class FieldService
      */
     public static function delField($id)
     {
+        Db::beginTransaction();
         try {
-            SysField::where('field_id', $id)->delete();
+            $field = SysField::where('field_id', $id)->first();
+            // 删除表记录
+            $field->delete();
+            // 删除表字段
+            Util::db()->statement("ALTER TABLE " . getenv('DB_PREFIX') . $field->field_table . " DROP COLUMN `$field->field_column_key`");
+            // 提交事务
+            Db::commit();
         } catch (\Exception $e) {
+            // 回滚
+            Db::rollBack();
             return json_fail('字段删除失败');
         }
 
         return json_success('字段删除成功');
     }
+
+    /**
+     * @Desc 验证表字段是否存在
+     * @Author Gorden
+     * @Date 2024/2/23 11:49
+     *
+     * @param $table
+     * @param $field
+     * @return bool
+     */
+    public static function checkFieldExist($table, $field)
+    {
+        return SysField::where('field_table', $table)
+            ->where('field_column_key', $field)
+            ->exists();
+    }
+
+    /**
+     * 创建字段
+     * @param $column
+     * @param Blueprint $table
+     * @return mixed
+     * @throws \Exception
+     */
+    public static function createColumn(Blueprint $table, $column)
+    {
+        $method = $column['type'];
+        $args = [$column['field']];
+        $type_method_map = Util::methodControlMap();
+        if (!isset($column['type'])) {
+            throw new \Exception("请为{$column['field']}选择类型");
+        }
+        if (!isset($type_method_map[$column['type']])) {
+            throw new \Exception("不支持的类型{$column['type']}");
+        }
+        if (stripos($method, 'int') !== false) {
+            // auto_increment 会自动成为主键
+            if ($column['auto_increment']) {
+                $column['nullable'] = false;
+                $column['default'] = null;
+                $args[] = true;
+            }
+        } elseif (in_array($method, ['string', 'char']) || stripos($method, 'time') !== false) {
+            if ($column['length']) {
+                $args[] = $column['length'];
+            }
+        } elseif ($method === 'enum') {
+            $args[] = array_map('trim', explode(',', $column['length']));
+        } elseif (in_array($method, ['float', 'decimal', 'double'])) {
+            if ($column['length']) {
+                $args = array_merge($args, array_map('trim', explode(',', $column['length'])));
+            }
+        } else {
+            $column['auto_increment'] = false;
+        }
+
+        $column_def = call_user_func_array([$table, $method], $args);
+        if (!empty($column['comment'])) {
+            $column_def = $column_def->comment($column['comment']);
+        }
+
+        if (!$column['auto_increment'] && $column['primary_key']) {
+            $column_def = $column_def->primary(true);
+        }
+
+        if ($column['auto_increment'] && !$column['primary_key']) {
+            $column_def = $column_def->primary(false);
+        }
+        $column_def = $column_def->nullable($column['nullable']);
+
+        if ($column['primary_key']) {
+            $column_def = $column_def->nullable(false);
+        }
+
+        if ($method != 'text' && $column['default'] !== null) {
+            $column_def->default($column['default']);
+        }
+        return $column_def;
+    }
+
+    /**
+     * 更改字段
+     * @param $column
+     * @param $table
+     * @return mixed
+     * @throws \Exception
+     */
+    protected static function modifyColumn($table, $column)
+    {
+        $method = $column['type'];
+        $field = $column['field'];
+        $old_field = $column['old_field'] ?? null;
+        $nullable = $column['nullable'];
+        $default = $column['default'] !== null ? Util::pdoQuote($column['default']) : null;
+        $comment = Util::pdoQuote($column['comment']);
+        $auto_increment = $column['auto_increment'];
+        $length = (int)$column['length'];
+
+        if ($column['primary_key']) {
+            $default = null;
+        }
+
+        if ($old_field && $old_field !== $field) {
+            $sql = "ALTER TABLE `$table` CHANGE COLUMN `$old_field` `$field` ";
+        } else {
+            $sql = "ALTER TABLE `$table` MODIFY `$field` ";
+        }
+
+        if (stripos($method, 'integer') !== false) {
+            $type = str_ireplace('integer', 'int', $method);
+            if (stripos($method, 'unsigned') !== false) {
+                $type = str_ireplace('unsigned', '', $type);
+                $sql .= "$type ";
+                $sql .= 'unsigned ';
+            } else {
+                $sql .= "$type ";
+            }
+            if ($auto_increment) {
+                $column['nullable'] = false;
+                $column['default'] = null;
+                $sql .= 'AUTO_INCREMENT ';
+            }
+        } else {
+            switch ($method) {
+                case 'string':
+                    $length = $length ?: 255;
+                    $sql .= "varchar($length) ";
+                    break;
+                case 'char':
+                case 'time':
+                    $sql .= $length ? "$method($length) " : "$method ";
+                    break;
+                case 'enum':
+                    $args = array_map('trim', explode(',', (string)$column['length']));
+                    foreach ($args as $key => $value) {
+                        $args[$key] = Util::pdoQuote($value);
+                    }
+                    $sql .= 'enum(' . implode(',', $args) . ') ';
+                    break;
+                case 'double':
+                case 'float':
+                case 'decimal':
+                    if (trim($column['length'])) {
+                        $args = array_map('intval', explode(',', $column['length']));
+                        $args[1] = $args[1] ?? $args[0];
+                        $sql .= "$method($args[0], $args[1]) ";
+                        break;
+                    }
+                    $sql .= "$method ";
+                    break;
+                default :
+                    $sql .= "$method ";
+
+            }
+        }
+
+        if (!$nullable) {
+            $sql .= "NOT NULL ";
+        }
+
+        if ($method != 'text' && $default !== null) {
+            $sql .= "DEFAULT $default ";
+        }
+
+        if ($comment !== null) {
+            $sql .= "COMMENT $comment ";
+        }
+
+        echo "$sql\n";
+        Util::db()->statement($sql);
+    }
+
 }

+ 17 - 5
app/admin/validate/sys_manage/FieldValidate.php

@@ -12,8 +12,8 @@ class FieldValidate extends Validate
         'field_name' => 'require|chsDash',
         'field_table' => 'require|alphaDash',
         'field_column_key' => 'alphaDash',
-        'field_column_datatype' => 'in:VARCHAR,DECIMAL,TEXT,DATE,DATETIME',
-//        'field_column_default' => 'chsDash',
+        'field_column_datatype' => 'in:string,decimal,text,dateTime',
+        'field_column_default' => 'checkDefault',
         'field_form_key' => 'in:id,name',
         'field_form_type' => 'alphaDash',
 //        'field_form_default' => 'chsDash',
@@ -25,8 +25,8 @@ class FieldValidate extends Validate
     protected $message = [];
 
     protected $scene = [
-        'add' => ['field_status', 'field_category', 'field_name', 'field_table', 'field_column_key', 'field_column_datatype', 'field_form_key', 'field_form_type', 'field_refer_json', 'field_extend_json'],
-        'update' => ['field_category', 'field_name', 'field_table', 'field_column_key', 'field_column_datatype', 'field_form_key', 'field_form_type', 'field_refer_json', 'field_extend_json'],
+        'add' => ['field_status', 'field_category', 'field_name', 'field_table', 'field_column_key', 'field_column_datatype', 'field_form_key', 'field_form_type', 'field_column_default', 'field_refer_json', 'field_extend_json'],
+        'update' => ['field_category', 'field_name', 'field_table', 'field_column_key', 'field_column_datatype', 'field_form_key', 'field_form_type', 'field_column_default', 'field_refer_json', 'field_extend_json'],
         'update_status' => ['field_status']
     ];
 
@@ -40,10 +40,22 @@ class FieldValidate extends Validate
      */
     protected function isJson($value)
     {
-        if (is_json($value)){
+        if (is_json($value)) {
             return true;
         }
 
         return '数据格式错误~';
     }
+
+    protected function checkDefault($value, $rule, $data)
+    {
+        if ($data['field_column_datatype'] == 'dateTime') {
+            if (strlen($value) >= 14 && false !== strtotime($value)) {
+                return true;
+            }
+
+            return "数据格式错误~ 例如:2024-01-01 12:00:00";
+        }
+        return true;
+    }
 }

+ 110 - 0
app/common/Util.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace app\common;
+
+use support\Db;
+use Illuminate\Database\Connection;
+use Illuminate\Database\Schema\Builder;
+
+class Util
+{
+    /**
+     * 获取webman-admin数据库连接
+     * @return Connection
+     */
+    public static function db(): Connection
+    {
+        return Db::connection('mysql');
+    }
+
+    /**
+     * 获取SchemaBuilder
+     * @return Builder
+     */
+    public static function schema(): Builder
+    {
+        return Db::schema('mysql');
+    }
+
+    /**
+     * 数据库字符串转义
+     * @param $var
+     * @return false|string
+     */
+    public static function pdoQuote($var)
+    {
+        return Util::db()->getPdo()->quote($var, \PDO::PARAM_STR);
+    }
+
+    /**
+     * 变量或数组中的元素只能是字母数字下划线组合
+     * @param $var
+     * @return mixed
+     * @throws \Exception
+     */
+    public static function filterAlphaNum($var)
+    {
+        $vars = (array)$var;
+        array_walk_recursive($vars, function ($item) {
+            if (is_string($item) && !preg_match('/^[a-zA-Z_0-9]+$/', $item)) {
+                throw new \Exception('参数不合法');
+            }
+        });
+        return $var;
+    }
+
+    public static function fieldDefaultLength()
+    {
+        return [
+            'string' => 255,    // 对应varchar
+            'integer' => 11,
+            'decimal' => '10,2',
+            'dateTime' => 0
+        ];
+    }
+
+    /**
+     * 表单类型到插件的映射
+     * @return \string[][]
+     */
+    public static function methodControlMap(): array
+    {
+        return [
+            //method=>[控件]
+            'integer' => ['InputNumber'],
+            'string' => ['Input'],
+            'text' => ['TextArea'],
+            'date' => ['DatePicker'],
+            'enum' => ['Select'],
+            'float' => ['Input'],
+
+            'tinyInteger' => ['InputNumber'],
+            'smallInteger' => ['InputNumber'],
+            'mediumInteger' => ['InputNumber'],
+            'bigInteger' => ['InputNumber'],
+
+            'unsignedInteger' => ['InputNumber'],
+            'unsignedTinyInteger' => ['InputNumber'],
+            'unsignedSmallInteger' => ['InputNumber'],
+            'unsignedMediumInteger' => ['InputNumber'],
+            'unsignedBigInteger' => ['InputNumber'],
+
+            'decimal' => ['Input'],
+            'double' => ['Input'],
+
+            'mediumText' => ['TextArea'],
+            'longText' => ['TextArea'],
+
+            'dateTime' => ['DateTimePicker'],
+
+            'time' => ['DateTimePicker'],
+            'timestamp' => ['DateTimePicker'],
+
+            'char' => ['Input'],
+
+            'binary' => ['Input'],
+
+            'json' => ['input']
+        ];
+    }
+}

+ 14 - 0
app/model/MemberInfo.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace app\model;
+
+use support\Model;
+
+class MemberInfo extends Model
+{
+    public $table = 'member_info';
+
+    public $primaryKey = 'join_info_member_id';
+
+    public const UPDATED_AT = null;
+}