From eccf03e43fe07657efc4ba6d01f963346561fc5a Mon Sep 17 00:00:00 2001 From: Karson <karsonzhang@163.com> Date: Fri, 15 Mar 2019 23:50:11 +0800 Subject: [PATCH] 新增一键CRUD类名冲突检测 新增一键CRUD自动传递请求参数 新增一键菜单之支持ThinkPHP5标准命名规则 新增Table.api.formatter.toggle自定义URL 新增Table.api.formatter.search自定义搜索字段 修复关联模型不同命名空间之间的BUG 优化时间字段修改器的判断 --- application/admin/command/Crud.php | 44 +++++++++++++++++++++++++++++--------------- application/admin/command/Crud/stubs/javascript.stub | 2 +- application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub | 2 +- application/admin/command/Crud/stubs/mixins/radio.stub | 2 +- application/admin/command/Crud/stubs/mixins/select.stub | 2 +- application/admin/command/Menu.php | 41 +++++++++++++++++++++++++++++++++-------- public/assets/js/require-table.js | 10 ++++++++-- 7 files changed, 74 insertions(+), 29 deletions(-) diff --git a/application/admin/command/Crud.php b/application/admin/command/Crud.php index eb4c89d..8850631 100755 --- a/application/admin/command/Crud.php +++ b/application/admin/command/Crud.php @@ -10,6 +10,7 @@ use think\console\input\Option; use think\console\Output; use think\Db; use think\Exception; +use think\exception\ErrorException; use think\Lang; use think\Loader; @@ -17,6 +18,9 @@ class Crud extends Command { protected $stubList = []; + protected $internalKeywords = [ + 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor' + ]; /** * Selectpage搜索字段关联 */ @@ -181,6 +185,7 @@ class Crud extends Command $controller = $input->getOption('controller'); //自定义模型 $model = $input->getOption('model'); + $model = $model ? $model : $controller; //验证器类 $validate = $model; //自定义显示字段 @@ -324,6 +329,8 @@ class Crud extends Command $relations[] = [ //关联表基础名 'relationName' => $relationName, + //关联表类命名空间 + 'relationNamespace' => $relationNamespace, //关联模型名 'relationModel' => $relationModel, //关联文件 @@ -369,6 +376,8 @@ class Crud extends Command //视图文件 $viewArr = $controllerArr; + $lastValue = array_pop($viewArr); + $viewArr[] = Loader::parseName($lastValue, 0); array_unshift($viewArr, 'view'); $viewDir = $adminPath . strtolower(implode(DS, $viewArr)) . DS; @@ -383,7 +392,7 @@ class Crud extends Command //是否为删除模式 $delete = $input->getOption('delete'); if ($delete) { - $readyFiles = [$controllerFile, $modelFile, $validateFile, $addFile, $editFile, $indexFile, $langFile, $javascriptFile]; + $readyFiles = [$controllerFile, $modelFile, $validateFile, $addFile, $editFile, $indexFile, $recyclebinFile, $langFile, $javascriptFile]; foreach ($readyFiles as $k => $v) { $output->warning($v); } @@ -409,6 +418,7 @@ class Crud extends Command case $addFile: case $editFile: case $indexFile: + case $recyclebinFile: $this->removeEmptyBaseDir($v, $viewArr); break; default: @@ -522,6 +532,7 @@ class Crud extends Command } $relation['relationForeignKey'] = $relationForeignKey; $relation['relationPrimaryKey'] = $relationPrimaryKey; + $relation['relationClassName'] = $modelNamespace != $relation['relationNamespace'] ? $relation['relationNamespace'] . '\\' . $relation['relationName'] : $relation['relationName']; } unset($relation); @@ -629,9 +640,8 @@ class Crud extends Command $defaultDateTime = "{:date('{$phpFormat}')}"; $attrArr['data-date-format'] = $format; $attrArr['data-use-current'] = "true"; - $fieldFunc = $fieldFunc ? "|{$fieldFunc}" : ""; $formAddElement = Form::text($fieldName, $defaultDateTime, $attrArr); - $formEditElement = Form::text($fieldName, "{\$row.{$field}{$fieldFunc}}", $attrArr); + $formEditElement = Form::text($fieldName, ($fieldFunc ? "{:\$row.{$field}?{$fieldFunc}(\$row.{$field}):''}" : "{\$row.{$field}{$fieldFunc}}"), $attrArr); } elseif ($inputType == 'checkbox' || $inputType == 'radio') { unset($attrArr['data-rule']); $fieldName = $inputType == 'checkbox' ? $fieldName .= "[]" : $fieldName; @@ -928,7 +938,7 @@ class Crud extends Command if ($langList) { $this->writeToFile('lang', $data, $langFile); } - } catch (think\exception\ErrorException $e) { + } catch (ErrorException $e) { throw new Exception("Code: " . $e->getCode() . "\nLine: " . $e->getLine() . "\nMessage: " . $e->getMessage() . "\nFile: " . $e->getFile()); } @@ -956,7 +966,7 @@ class Crud extends Command public function {$methodName}() { return [{$itemString}]; - } + } EOD; $controllerAssignList[] = <<<EOD \$this->view->assign("{$fieldList}", \$this->model->{$methodName}()); @@ -980,7 +990,7 @@ EOD; $attrField = ucfirst($this->getCamelizeName($field)); if ($inputType == 'datetime') { $return = <<<EOD -return \$value && !is_numeric(\$value) ? strtotime(\$value) : \$value; +return \$value === '' ? null : (\$value && !is_numeric(\$value) ? strtotime(\$value) : \$value); EOD; } elseif (in_array($inputType, ['checkbox', 'select'])) { $return = <<<EOD @@ -1069,9 +1079,9 @@ EOD; /** * 获取已解析相关信息 * @param string $module 模块名称 - * @param string $name 自定义名称 - * @param string $table 数据表名 - * @param string $type 解析类型,本例中为controller、model、validate + * @param string $name 自定义名称 + * @param string $table 数据表名 + * @param string $type 解析类型,本例中为controller、model、validate * @return array */ protected function getParseNameData($module, $name, $table, $type) @@ -1087,6 +1097,10 @@ EOD; $parseArr = $arr; array_push($parseArr, $parseName); } + //类名不能为内部关键字 + if (in_array(strtolower($parseName), $this->internalKeywords)) { + throw new Exception('Unable to use internal variable:' . $parseName); + } $appNamespace = Config::get('app_namespace'); $parseNamespace = "{$appNamespace}\\{$module}\\{$type}" . ($arr ? "\\" . implode("\\", $arr) : ""); $moduleDir = APP_PATH . $module . DS; @@ -1097,7 +1111,7 @@ EOD; /** * 写入到文件 * @param string $name - * @param array $data + * @param array $data * @param string $pathname * @return mixed */ @@ -1118,7 +1132,7 @@ EOD; /** * 获取替换后的数据 * @param string $name - * @param array $data + * @param array $data * @return string */ protected function getReplacedStub($name, $data) @@ -1183,7 +1197,7 @@ EOD; /** * 读取数据和语言数组列表 - * @param array $arr + * @param array $arr * @param boolean $withTpl * @return array */ @@ -1303,8 +1317,8 @@ EOD; /** * 判断是否符合指定后缀 - * @param string $field 字段名称 - * @param mixed $suffixArr 后缀 + * @param string $field 字段名称 + * @param mixed $suffixArr 后缀 * @return boolean */ protected function isMatchSuffix($field, $suffixArr) @@ -1371,7 +1385,7 @@ EOD; * @param string $field * @param string $datatype * @param string $extend - * @param array $itemArr + * @param array $itemArr * @return string */ protected function getJsColumn($field, $datatype = '', $extend = '', $itemArr = []) diff --git a/application/admin/command/Crud/stubs/javascript.stub b/application/admin/command/Crud/stubs/javascript.stub index 12fbb70..933cfa3 100644 --- a/application/admin/command/Crud/stubs/javascript.stub +++ b/application/admin/command/Crud/stubs/javascript.stub @@ -5,7 +5,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin // 初始化表格参数配置 Table.api.init({ extend: { - index_url: '{%controllerUrl%}/index', + index_url: '{%controllerUrl%}/index' + location.search, add_url: '{%controllerUrl%}/add', edit_url: '{%controllerUrl%}/edit', del_url: '{%controllerUrl%}/del', diff --git a/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub b/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub index 712daeb..3da6462 100755 --- a/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub +++ b/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub @@ -1,5 +1,5 @@ public function {%relationMethod%}() { - return $this->{%relationMode%}('{%relationName%}', '{%relationForeignKey%}', '{%relationPrimaryKey%}', [], 'LEFT')->setEagerlyType(0); + return $this->{%relationMode%}('{%relationClassName%}', '{%relationForeignKey%}', '{%relationPrimaryKey%}', [], 'LEFT')->setEagerlyType(0); } \ No newline at end of file diff --git a/application/admin/command/Crud/stubs/mixins/radio.stub b/application/admin/command/Crud/stubs/mixins/radio.stub index 527151a..71234a6 100644 --- a/application/admin/command/Crud/stubs/mixins/radio.stub +++ b/application/admin/command/Crud/stubs/mixins/radio.stub @@ -1,6 +1,6 @@ public function {%methodName%}($value, $data) - { + { $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : ''); $list = $this->{%listMethodName%}(); return isset($list[$value]) ? $list[$value] : ''; diff --git a/application/admin/command/Crud/stubs/mixins/select.stub b/application/admin/command/Crud/stubs/mixins/select.stub index 527151a..71234a6 100644 --- a/application/admin/command/Crud/stubs/mixins/select.stub +++ b/application/admin/command/Crud/stubs/mixins/select.stub @@ -1,6 +1,6 @@ public function {%methodName%}($value, $data) - { + { $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : ''); $list = $this->{%listMethodName%}(); return isset($list[$value]) ? $list[$value] : ''; diff --git a/application/admin/command/Menu.php b/application/admin/command/Menu.php index affe024..02ec31f 100755 --- a/application/admin/command/Menu.php +++ b/application/admin/command/Menu.php @@ -12,6 +12,7 @@ use think\console\Input; use think\console\input\Option; use think\console\Output; use think\Exception; +use think\Loader; class Menu extends Command { @@ -52,6 +53,18 @@ class Menu extends Command $ids = []; $list = $this->model->where(function ($query) use ($controller, $equal) { foreach ($controller as $index => $item) { + if (stripos($item, '_') !== false) { + $item = Loader::parseName($item, 1); + } + if (stripos($item, '/') !== false) { + $controllerArr = explode('/', $item); + end($controllerArr); + $key = key($controllerArr); + $controllerArr[$key] = Loader::parseName($controllerArr[$key]); + } else { + $controllerArr = [Loader::parseName($item)]; + } + $item = str_replace('_', '\_', implode('/', $controllerArr)); if ($equal) { $query->whereOr('name', 'eq', $item); } else { @@ -82,10 +95,17 @@ class Menu extends Command if (!in_array('all-controller', $controller)) { foreach ($controller as $index => $item) { - $controllerArr = explode('/', $item); - end($controllerArr); - $key = key($controllerArr); - $controllerArr[$key] = ucfirst($controllerArr[$key]); + if (stripos($item, '_') !== false) { + $item = Loader::parseName($item, 1); + } + if (stripos($item, '/') !== false) { + $controllerArr = explode('/', $item); + end($controllerArr); + $key = key($controllerArr); + $controllerArr[$key] = ucfirst($controllerArr[$key]); + } else { + $controllerArr = [ucfirst($item)]; + } $adminPath = dirname(__DIR__) . DS . 'controller' . DS . implode(DS, $controllerArr) . '.php'; if (!is_file($adminPath)) { $output->error("controller not found"); @@ -159,10 +179,15 @@ class Menu extends Command protected function importRule($controller) { $controller = str_replace('\\', '/', $controller); - $controllerArr = explode('/', $controller); - end($controllerArr); - $key = key($controllerArr); - $controllerArr[$key] = ucfirst($controllerArr[$key]); + if (stripos($controller, '/') !== false) { + $controllerArr = explode('/', $controller); + end($controllerArr); + $key = key($controllerArr); + $controllerArr[$key] = ucfirst($controllerArr[$key]); + } else { + $key = 0; + $controllerArr = [ucfirst($controller)]; + } $classSuffix = Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : ''; $className = "\\app\\admin\\controller\\" . implode("\\", $controllerArr) . $classSuffix; diff --git a/public/assets/js/require-table.js b/public/assets/js/require-table.js index 6b28bf3..151535b 100644 --- a/public/assets/js/require-table.js +++ b/public/assets/js/require-table.js @@ -479,14 +479,20 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table var color = typeof this.color !== 'undefined' ? this.color : 'success'; var yes = typeof this.yes !== 'undefined' ? this.yes : 1; var no = typeof this.no !== 'undefined' ? this.no : 0; + var url = typeof this.url !== 'undefined' ? this.url : ''; return "<a href='javascript:;' data-toggle='tooltip' title='" + __('Click to toggle') + "' class='btn-change' data-id='" - + row.id + "' data-params='" + this.field + "=" + (value == yes ? no : yes) + "'><i class='fa fa-toggle-on " + (value == yes ? 'text-' + color : 'fa-flip-horizontal text-gray') + " fa-2x'></i></a>"; + + row.id + "' " + (url ? "data-url='" + url + "'" : "") + " data-params='" + this.field + "=" + (value == yes ? no : yes) + "'><i class='fa fa-toggle-on " + (value == yes ? 'text-' + color : 'fa-flip-horizontal text-gray') + " fa-2x'></i></a>"; }, url: function (value, row, index) { return '<div class="input-group input-group-sm" style="width:250px;margin:0 auto;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>'; }, search: function (value, row, index) { - return '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', value) + '" data-field="' + this.field + '" data-value="' + value + '">' + value + '</a>'; + var field = this.field; + if (typeof this.customField !== 'undefined' && typeof row[this.customField] !== 'undefined') { + value = row[this.customField]; + field = this.customField; + } + return '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', value) + '" data-field="' + field + '" data-value="' + value + '">' + value + '</a>'; }, addtabs: function (value, row, index) { var url = Table.api.replaceurl(this.url, row, this.table); -- libgit2 0.24.0