Просмотр исходного кода

Merge pull request #22 from jqhph/master

拉取最新版本
yxx 5 лет назад
Родитель
Сommit
0bda760933
45 измененных файлов с 398 добавлено и 191 удалено
  1. 8 6
      README.md
  2. 10 2
      config/admin.php
  3. 4 4
      resources/assets/adminlte/scss/_main-sidebar.scss
  4. 58 1
      resources/assets/dcat/sass/components/_menu.scss
  5. 11 4
      resources/assets/dcat/sass/components/_table.scss
  6. 7 0
      resources/assets/dcat/sass/theme/_dark.scss
  7. BIN
      resources/assets/images/pages/login/bg.jpg
  8. BIN
      resources/assets/images/waves.png
  9. 0 0
      resources/dist/adminlte/adminlte-blue-dark.css
  10. 0 0
      resources/dist/adminlte/adminlte-blue-light.css
  11. 0 0
      resources/dist/adminlte/adminlte-blue.css
  12. 0 0
      resources/dist/adminlte/adminlte-green.css
  13. 0 0
      resources/dist/adminlte/adminlte.css
  14. 0 0
      resources/dist/adminlte/adminlte.js.map
  15. 0 0
      resources/dist/dcat/css/dcat-app-blue-dark.css
  16. 0 0
      resources/dist/dcat/css/dcat-app-blue-light.css
  17. 0 0
      resources/dist/dcat/css/dcat-app-blue.css
  18. 0 0
      resources/dist/dcat/css/dcat-app-green.css
  19. 0 0
      resources/dist/dcat/css/dcat-app.css
  20. 0 0
      resources/dist/dcat/extra/action.js.map
  21. 0 0
      resources/dist/dcat/extra/resource-selector.js.map
  22. 0 0
      resources/dist/dcat/js/dcat-app.js.map
  23. BIN
      resources/dist/images/pages/login/bg.jpg
  24. BIN
      resources/dist/images/waves.png
  25. 6 1
      resources/views/form/checkbox.blade.php
  26. 2 0
      src/Admin.php
  27. 4 4
      src/Application.php
  28. 1 1
      src/Console/ExtendCommand.php
  29. 16 8
      src/Console/stubs/config.stub
  30. 5 4
      src/Form.php
  31. 1 0
      src/Form/EmbeddedForm.php
  32. 43 7
      src/Form/Field.php
  33. 88 0
      src/Form/Field/ArrayField.php
  34. 38 0
      src/Form/Field/Checkbox.php
  35. 13 7
      src/Form/Field/Map.php
  36. 1 91
      src/Form/Field/Table.php
  37. 0 7
      src/Grid.php
  38. 24 6
      src/Grid/Column.php
  39. 11 10
      src/Grid/Displayers/Checkbox.php
  40. 13 10
      src/Grid/Displayers/Radio.php
  41. 6 4
      src/Grid/Displayers/Select.php
  42. 11 7
      src/Grid/Displayers/SwitchDisplay.php
  43. 10 7
      src/Grid/Displayers/SwitchGroup.php
  44. 6 0
      src/Support/Helper.php
  45. 1 0
      src/Widgets/Form.php

+ 8 - 6
README.md

@@ -30,17 +30,19 @@
 
 ## 截图
 
-![](https://cdn.learnku.com/uploads/images/202007/24/38389/4bCfBdtvq5.png!large)
+![](https://cdn.learnku.com/uploads/images/202008/08/38389/YRZvU7LEq9.jpg!large)
 
-![](https://cdn.learnku.com/uploads/images/202007/24/38389/35KJXfVXib.png!large)
+![](https://cdn.learnku.com/uploads/images/202008/08/38389/F4PRdaiGrP.jpg!large)
+![](https://cdn.learnku.com/uploads/images/202008/08/38389/B7ALEoKOPn.jpg!large)
 
-![](https://cdn.learnku.com/uploads/images/202004/24/38389/GBkt9jYnW0.png!large)
+![](https://cdn.learnku.com/uploads/images/202008/08/38389/HNom4eX9xr.jpg!large)
 
-![](https://cdn.learnku.com/uploads/images/202007/12/38389/DUzCgtpPi8.png!large)
+![](https://cdn.learnku.com/uploads/images/202008/08/38389/RnExzKgH8T.jpg!large)
 
-![](https://cdn.learnku.com/uploads/images/202007/23/38389/sdgD7s9DP4.png!large)
+![](https://cdn.learnku.com/uploads/images/202008/08/38389/O67S62aI4s.jpg!large)
+
+![](https://cdn.learnku.com/uploads/images/202008/08/38389/lGYIdhifb5.jpg!large)
 
-![](https://cdn.learnku.com/uploads/images/202007/12/38389/fjSNhbtg6f.png!large)
 
 ## 功能特性
 

+ 10 - 2
config/admin.php

@@ -300,10 +300,18 @@ return [
     | Admin map field provider
     |--------------------------------------------------------------------------
     |
-    | Supported: "tencent", "google", "yandex".
+    | Supported: "tencent", "google", "yandex", "baidu".
     |
     */
-    'map_provider' => 'google',
+    'map' => [
+        'provider' => 'baidu',
+
+        'keys' => [
+            'tencent' => env('TENCENT_MAP_API_KEY'),
+            'google' => env('GOOGLE_API_KEY'),
+            'baidu' => env('BAIDU_MAP_API_KEY'),
+        ],
+    ],
 
     /*
     |--------------------------------------------------------------------------

+ 4 - 4
resources/assets/adminlte/scss/_main-sidebar.scss

@@ -22,13 +22,13 @@
 
   .nav-treeview.nav {
     .nav-item .nav-link {
-      padding: 7px 10px 7px 15px!important;
+      padding: 5px 10px 7px 15px!important;
       //margin-right: 0;
     }
 
-    .nav-item .nav-link.active {
-      padding: 8px 10px 8px 15px!important;
-    }
+    //.nav-item .nav-link.active {
+    //    //  padding: 8px 10px 8px 15px!important;
+    //    //}
   }
 }
 

+ 58 - 1
resources/assets/dcat/sass/components/_menu.scss

@@ -1,4 +1,3 @@
-
 .main-menu {
   .navbar-header {
     padding: 0.35rem 1rem 0;
@@ -98,3 +97,61 @@ body.sidebar-collapse {
   }
 }
 
+[class*=sidebar-light-] .nav-treeview>.nav-item>.nav-link.active, [class*=sidebar-light-] .nav-treeview>.nav-item>.nav-link.active:hover {
+  color: $primary-darker;
+  background: none;
+  box-shadow: 0 0;
+}
+
+.sidebar-light-primary .nav-item > .nav-link.active {
+  background: none;
+  color: $primary-darker !important;
+  font-weight: bold;
+  box-shadow: 0 0;
+}
+
+.nav-sidebar>.nav-item>.nav-treeview  .nav-link p {
+  font-size: 14px;
+}
+
+// ----- sidebar-separate
+body.sidebar-separate {
+  .main-sidebar {
+    top: 6rem;
+    left: 1.5rem;
+    text-align: center;
+    background: url(/vendors/dcat-admin/images/waves.png) no-repeat;
+    background-color: #fff;
+  }
+
+  .navbar-header {
+    .logo-lg,
+    .logo-mini {
+      color: $font-color;
+    }
+
+    .navbar-brand {
+      margin-top: 1rem;
+    }
+  }
+
+  .header-navbar.fixed-top,
+  .sidebar-collapse .header-navbar.fixed-top {
+    left: 0;
+  }
+
+  @media (min-width: 768px) {
+    .content-wrapper {
+      margin-left: 280px;
+    }
+  }
+
+  .main-sidebar .nav-sidebar .nav-item>.nav-link {
+    text-align: left;
+  }
+}
+
+body.sidebar-separate.dark-mode [class*=sidebar-dark-] .navbar-header {
+  background: unset!important;
+}
+

+ 11 - 4
resources/assets/dcat/sass/components/_table.scss

@@ -203,17 +203,20 @@ $table-border-color: #eff3f8;
   }
 }
 
+
+$table-bg: darken(#f7f7f9, 3.5%);
+
 body:not(.dark-mode) {
   .table-collapse {
     box-shadow: $shadow;
-    background: darken(#f7f7f9, 3.5%);
+    background: $table-bg;
     margin-top: 1rem;
 
     .custom-data-table {
       border-spacing: 0;
       //border-collapse:collapse!important;
       margin-top: 0!important;
-      background-color: darken(#f7f7f9, 3.5%);
+      background-color: $table-bg;
       //border-radius: $card-border-radius;
     }
 
@@ -225,9 +228,13 @@ body:not(.dark-mode) {
       //background: $white;
     }
 
-    table.custom-data-table.dataTable tbody td {
+    .custom-data-table.dataTable tbody td {
       border-top: 1px solid $table-border-color;
-      height: 42px;
+      height: 45px;
+    }
+
+    .custom-data-table.dataTable tbody tr:first-child td {
+      border-top: 0
     }
 
     table.custom-data-table.dataTable tbody tr {

+ 7 - 0
resources/assets/dcat/sass/theme/_dark.scss

@@ -867,4 +867,11 @@ body.dark-mode {
       padding: 10px 10px 10px 15px !important;
     }
   }
+
+  .main-sidebar .sidebar {
+    margin-top: 1rem
+  }
+  .main-menu .navbar-header .navbar-brand {
+    margin-top: .5rem;
+  }
 }

BIN
resources/assets/images/pages/login/bg.jpg


BIN
resources/assets/images/waves.png


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/adminlte/adminlte-blue-dark.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/adminlte/adminlte-blue-light.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/adminlte/adminlte-blue.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/adminlte/adminlte-green.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/adminlte/adminlte.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/adminlte/adminlte.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/css/dcat-app-blue-dark.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/css/dcat-app-blue-light.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/css/dcat-app-blue.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/css/dcat-app-green.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/css/dcat-app.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/extra/action.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/extra/resource-selector.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
resources/dist/dcat/js/dcat-app.js.map


BIN
resources/dist/images/pages/login/bg.jpg


BIN
resources/dist/images/waves.png


+ 6 - 1
resources/views/form/checkbox.blade.php

@@ -1,9 +1,14 @@
 <div class="{{$viewClass['form-group']}} {!! !$errors->has($column) ?: 'has-error' !!}" >
 
-    <label for="{{$id}}" class="{{$viewClass['label']}} control-label">{!! $label !!}</label>
+    <label for="{{$id}}" class="{{$viewClass['label']}} control-label pt-0">{!! $label !!}</label>
 
     <div class="{{$viewClass['field']}}" id="{{ $id }}">
 
+        @if($checkAll)
+            {!! $checkAll !!}
+            <hr style="margin-top: 10px;margin-bottom: 0;">
+        @endif
+
         @include('admin::form.error')
 
         {!! $checkbox !!}

+ 2 - 0
src/Admin.php

@@ -207,6 +207,7 @@ class Admin
         $attributes = [
             'prefix'     => config('admin.route.prefix'),
             'middleware' => config('admin.route.middleware'),
+            'as'         => static::app()->getName().'.',
         ];
 
         if (config('admin.auth.enable', true)) {
@@ -282,6 +283,7 @@ class Admin
         $attributes = [
             'prefix'     => config('admin.route.prefix'),
             'middleware' => config('admin.route.middleware'),
+            'as'         => static::app()->getName().'.',
         ];
 
         app('router')->group($attributes, function ($router) {

+ 4 - 4
src/Application.php

@@ -81,7 +81,7 @@ class Application
         if ($this->apps) {
             $this->registerMultiAppRoutes();
 
-            $this->withConfig(static::DEFAULT);
+            $this->switch(static::DEFAULT);
         }
     }
 
@@ -97,13 +97,13 @@ class Application
         if ($this->apps) {
             foreach ($this->apps as $app => $enable) {
                 if ($enable) {
-                    $this->withConfig($app);
+                    $this->switch($app);
 
                     $this->loadRoutesFrom($pathOrCallback, $app);
                 }
             }
 
-            $this->withConfig(static::DEFAULT);
+            $this->switch(static::DEFAULT);
         }
     }
 
@@ -141,7 +141,7 @@ class Application
      */
     protected function registerRoute(?string $app)
     {
-        $this->withConfig($app);
+        $this->switch($app);
 
         $this->loadRoutesFrom(function () use ($app) {
             Admin::registerApiRoutes($this->getApiRoutePrefix($app));

+ 1 - 1
src/Console/ExtendCommand.php

@@ -82,7 +82,7 @@ class ExtendCommand extends Command
 
         $this->package = $this->argument('extension');
 
-        InputExtensionName:
+        InputExtensionName :
         if (! Helper::validateExtensionName($this->package)) {
             $this->package = $this->ask("[$this->package] is not a valid package name, please input a name like (<vendor>/<name>)");
             goto InputExtensionName;

+ 16 - 8
src/Console/stubs/config.stub

@@ -296,14 +296,22 @@ return [
     ],
 
     /*
-    |--------------------------------------------------------------------------
-    | Admin map field provider
-    |--------------------------------------------------------------------------
-    |
-    | Supported: "tencent", "google", "yandex".
-    |
-    */
-    'map_provider' => 'google',
+	|--------------------------------------------------------------------------
+	| Admin map field provider
+	|--------------------------------------------------------------------------
+	|
+	| Supported: "tencent", "google", "yandex", "baidu".
+	|
+	*/
+	'map' => [
+		'provider' => 'baidu',
+
+		'keys' => [
+			'tencent' => env('TENCENT_MAP_API_KEY'),
+			'google' => env('GOOGLE_API_KEY'),
+			'baidu' => env('BAIDU_MAP_API_KEY'),
+		],
+	],
 
     /*
     |--------------------------------------------------------------------------

+ 5 - 4
src/Form.php

@@ -23,7 +23,6 @@ use Illuminate\Support\Arr;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Fluent;
 use Illuminate\Support\MessageBag;
-use Illuminate\Support\Str;
 use Illuminate\Support\Traits\Macroable;
 use Illuminate\Validation\Validator;
 use Symfony\Component\HttpFoundation\Response;
@@ -83,6 +82,7 @@ use Symfony\Component\HttpFoundation\Response;
  * @method Field\Markdown               markdown($column, $label = '')
  * @method Field\Range                  range($start, $end, $label = '')
  * @method Field\Color                  color($column, $label = '')
+ * @method Field\ArrayField             array($column, $labelOrCallback, $callback = null)
  */
 class Form implements Renderable
 {
@@ -162,6 +162,7 @@ class Form implements Renderable
         'markdown'       => Field\Markdown::class,
         'range'          => Field\Range::class,
         'color'          => Field\Color::class,
+        'array'          => Field\ArrayField::class,
     ];
 
     /**
@@ -686,10 +687,10 @@ class Form implements Renderable
             if ($field instanceof Field\Display || $field->getAttribute('readonly') || $field->getAttribute('disabled')) {
                 return $field->column();
             }
-        })->filter()->toArray();
+        })->filter();
 
-        if ($ignored) {
-            Arr::forget($input, $ignored);
+        if (! $ignored->isEmpty()) {
+            Arr::forget($input, $ignored->flatten()->toArray());
         }
 
         return $input;

+ 1 - 0
src/Form/EmbeddedForm.php

@@ -60,6 +60,7 @@ use Illuminate\Support\Collection;
  * @method Field\Markdown               markdown($column, $label = '')
  * @method Field\Range                  range($start, $end, $label = '')
  * @method Field\Color                  color($column, $label = '')
+ * @method Field\ArrayField             array($column, $labelOrCallback, $callback = null)
  */
 class EmbeddedForm
 {

+ 43 - 7
src/Form/Field.php

@@ -209,9 +209,9 @@ class Field implements Renderable
     protected $labelClass = [];
 
     /**
-     * @var \Closure
+     * @var \Closure[]
      */
-    protected $savingCallback;
+    protected $savingCallbacks = [];
 
     /**
      * Field constructor.
@@ -847,7 +847,7 @@ class Field implements Renderable
      */
     public function saving(\Closure $closure)
     {
-        $this->savingCallback = $closure;
+        $this->savingCallbacks[] = $closure;
 
         return $this;
     }
@@ -863,10 +863,10 @@ class Field implements Renderable
     {
         $value = $this->prepareInputValue($value);
 
-        if ($handler = $this->savingCallback) {
-            $handler->bindTo($this->data());
-
-            return $handler($value);
+        if ($this->savingCallbacks) {
+            foreach ($this->savingCallbacks as $callback) {
+                $value = $callback->call($this->data(), $value);
+            }
         }
 
         return $value;
@@ -1193,6 +1193,42 @@ class Field implements Renderable
         return $this->display;
     }
 
+    public function saveAsJson($option = 0)
+    {
+        return $this->saving(function ($value) use ($option) {
+            if (! $value || is_scalar($value)) {
+                return $value;
+            }
+
+            return json_encode($value, $option);
+        });
+    }
+
+    public function saveAsJoin(string $glue = ',')
+    {
+        return $this->saving(function ($value) use ($glue) {
+            if (! $value || is_scalar($value)) {
+                return $value;
+            }
+
+            return implode($glue, (array) $value);
+        });
+    }
+
+    public function saveAsString()
+    {
+        return $this->saving(function ($value) {
+            return (string) $value;
+        });
+    }
+
+    public function saveAsInteger()
+    {
+        return $this->saving(function ($value) {
+            return (int) $value;
+        });
+    }
+
     /**
      * Collect assets required by this field.
      */

+ 88 - 0
src/Form/Field/ArrayField.php

@@ -0,0 +1,88 @@
+<?php
+
+namespace Dcat\Admin\Form\Field;
+
+use Dcat\Admin\Form\NestedForm;
+use Dcat\Admin\Support\Helper;
+
+class ArrayField extends HasMany
+{
+    public function __construct($column, $arguments = [])
+    {
+        $this->column = $column;
+
+        if (count($arguments) == 1) {
+            $this->label = $this->formatLabel();
+            $this->builder = $arguments[0];
+        } elseif (count($arguments) == 2) {
+            [$this->label, $this->builder] = $arguments;
+        }
+    }
+
+    protected function buildRelatedForms()
+    {
+        if (is_null($this->form)) {
+            return [];
+        }
+
+        $forms = [];
+
+        if ($values = old($this->column)) {
+            foreach ($values as $key => $data) {
+                if ($data[NestedForm::REMOVE_FLAG_NAME] == 1) {
+                    continue;
+                }
+
+                $forms[$key] = $this->buildNestedForm($key)->fill($data);
+            }
+        } else {
+            foreach ($this->value() as $key => $data) {
+                if (isset($data['pivot'])) {
+                    $data = array_merge($data, $data['pivot']);
+                }
+
+                $forms[$key] = $this->buildNestedForm($key)->fill($data);
+            }
+        }
+
+        return $forms;
+    }
+
+    protected function prepareInputValue($input)
+    {
+        return collect($this->buildNestedForm()->prepare($input))
+            ->filter(function ($item) {
+                return empty($item[NestedForm::REMOVE_FLAG_NAME]);
+            })
+            ->transform(function ($item) {
+                unset($item[NestedForm::REMOVE_FLAG_NAME]);
+
+                return $item;
+            })
+            ->values()
+            ->toArray();
+    }
+
+    public function value($value = null)
+    {
+        if ($value === null) {
+            return Helper::array(parent::value($value));
+        }
+
+        return parent::value($value);
+    }
+
+    public function buildNestedForm($key = null)
+    {
+        $form = new NestedForm($this->column);
+
+        $form->setForm($this->form)
+            ->setKey($key);
+
+        call_user_func($this->builder, $form);
+
+        $form->hidden(NestedForm::REMOVE_FLAG_NAME)->default(0)->addElementClass(NestedForm::REMOVE_FLAG_CLASS);
+
+        return $form;
+    }
+}

+ 38 - 0
src/Form/Field/Checkbox.php

@@ -2,6 +2,7 @@
 
 namespace Dcat\Admin\Form\Field;
 
+use Dcat\Admin\Admin;
 use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Widgets\Checkbox as WidgetCheckbox;
 
@@ -16,6 +17,8 @@ class Checkbox extends MultipleSelect
 
     protected $cascadeEvent = 'change';
 
+    protected $canCheckAll = false;
+
     /**
      * @param array|\Closure|string $options
      *
@@ -48,6 +51,18 @@ class Checkbox extends MultipleSelect
         return $this;
     }
 
+    /**
+     * Add a checkbox above this component, so you can select all checkboxes by click on it.
+     *
+     * @return $this
+     */
+    public function canCheckAll()
+    {
+        $this->canCheckAll = true;
+
+        return $this;
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -78,10 +93,33 @@ class Checkbox extends MultipleSelect
 
         $this->addVariables([
             'checkbox' => $checkbox,
+            'checkAll' => $this->makeCheckAllCheckbox(),
         ]);
 
         $this->script = ';';
 
         return parent::render();
     }
+
+    protected function makeCheckAllCheckbox()
+    {
+        if (! $this->canCheckAll) {
+            return;
+        }
+
+        $this->addCheckAllScript();
+
+        return WidgetCheckbox::make('_check_all_', [__('admin.all')]);
+    }
+
+    protected function addCheckAllScript()
+    {
+        Admin::script(
+            <<<'JS'
+$('[name="_check_all_"]').on('change', function () {
+    $(this).parents('.form-field').find('input[type="checkbox"]').prop('checked', this.checked);
+});
+JS
+        );
+    }
 }

+ 13 - 7
src/Form/Field/Map.php

@@ -21,21 +21,23 @@ class Map extends Field
      */
     public static function collectAssets()
     {
-        switch (config('admin.map_provider')) {
+        $keys = config('admin.map.keys');
+
+        switch (static::getUsingMap()) {
             case 'tencent':
-                $js = '//map.qq.com/api/js?v=2.exp&key='.env('TENCENT_MAP_API_KEY');
+                $js = '//map.qq.com/api/js?v=2.exp&key='.($keys['tencent'] ?? env('TENCENT_MAP_API_KEY'));
                 break;
             case 'google':
-                $js = '//maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&key='.env('GOOGLE_API_KEY');
+                $js = '//maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&key='.($keys['google'] ?? env('GOOGLE_API_KEY'));
                 break;
             case 'yandex':
                 $js = '//api-maps.yandex.ru/2.1/?lang=ru_RU';
                 break;
             case 'baidu':
-                $js = '//api.map.baidu.com/api?v=2.0&ak=' . env('BAIDU_MAP_API_KEY');
+                $js = '//api.map.baidu.com/api?v=2.0&ak='.($keys['baidu'] ?? env('BAIDU_MAP_API_KEY'));
                 break;
             default:
-                $js = '//api.map.baidu.com/api?v=2.0&ak=' . env('BAIDU_MAP_API_KEY');
+                $js = '//api.map.baidu.com/api?v=2.0&ak='.($keys['baidu'] ?? env('BAIDU_MAP_API_KEY'));
         }
 
         Admin::js($js);
@@ -55,7 +57,7 @@ class Map extends Field
          * Google map is blocked in mainland China
          * people in China can use Tencent map instead(;
          */
-        switch (config('admin.map_provider')) {
+        switch (static::getUsingMap()) {
             case 'tencent':
                 $this->useTencentMap();
                 break;
@@ -73,6 +75,11 @@ class Map extends Field
         }
     }
 
+    protected static function getUsingMap()
+    {
+        return config('admin.map.provider') ?: config('admin.map_provider');
+    }
+
     public function useGoogleMap()
     {
         $this->script = <<<JS
@@ -269,6 +276,5 @@ JS;
             initBaiduMap('{$this->id['lat']}{$this->id['lng']}');
         })()
 JS;
-
     }
 }

+ 1 - 91
src/Form/Field/Table.php

@@ -3,104 +3,14 @@
 namespace Dcat\Admin\Form\Field;
 
 use Dcat\Admin\Admin;
-use Dcat\Admin\Form\NestedForm;
-use Dcat\Admin\Support\Helper;
 
-class Table extends HasMany
+class Table extends ArrayField
 {
     /**
      * @var string
      */
     protected $viewMode = 'table';
 
-    /**
-     * Table constructor.
-     *
-     * @param string $column
-     * @param array  $arguments
-     */
-    public function __construct($column, $arguments = [])
-    {
-        $this->column = $column;
-
-        if (count($arguments) == 1) {
-            $this->label = $this->formatLabel();
-            $this->builder = $arguments[0];
-        } elseif (count($arguments) == 2) {
-            [$this->label, $this->builder] = $arguments;
-        }
-    }
-
-    /**
-     * @return array
-     */
-    protected function buildRelatedForms()
-    {
-        if (is_null($this->form)) {
-            return [];
-        }
-
-        $forms = [];
-
-        if ($values = old($this->column)) {
-            foreach ($values as $key => $data) {
-                if ($data[NestedForm::REMOVE_FLAG_NAME] == 1) {
-                    continue;
-                }
-
-                $forms[$key] = $this->buildNestedForm($key)->fill($data);
-            }
-        } else {
-            foreach ($this->value() as $key => $data) {
-                if (isset($data['pivot'])) {
-                    $data = array_merge($data, $data['pivot']);
-                }
-
-                $forms[$key] = $this->buildNestedForm($key)->fill($data);
-            }
-        }
-
-        return $forms;
-    }
-
-    protected function prepareInputValue($input)
-    {
-        return collect($this->buildNestedForm()->prepare($input))
-            ->filter(function ($item) {
-                return empty($item[NestedForm::REMOVE_FLAG_NAME]);
-            })
-            ->transform(function ($item) {
-                unset($item[NestedForm::REMOVE_FLAG_NAME]);
-
-                return $item;
-            })
-            ->values()
-            ->toArray();
-    }
-
-    public function value($value = null)
-    {
-        if ($value === null) {
-            return Helper::array(parent::value($value));
-        }
-
-        return parent::value($value);
-    }
-
-    public function buildNestedForm($key = null)
-    {
-        $form = new NestedForm($this->column);
-
-        $form->setForm($this->form)
-            ->setKey($key);
-
-        call_user_func($this->builder, $form);
-
-        $form->hidden(NestedForm::REMOVE_FLAG_NAME)->default(0)->addElementClass(NestedForm::REMOVE_FLAG_CLASS);
-
-        return $form;
-    }
-
     public function render()
     {
         if (! $this->shouldRender()) {

+ 0 - 7
src/Grid.php

@@ -15,7 +15,6 @@ use Dcat\Admin\Traits\HasBuilderEvents;
 use Illuminate\Contracts\Support\Renderable;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Support\Collection;
-use Illuminate\Support\Str;
 use Illuminate\Support\Traits\Macroable;
 
 class Grid
@@ -253,12 +252,6 @@ class Grid
      */
     public function column($name, $label = '')
     {
-        if (mb_strpos($name, '.') !== false) {
-            [$relationName, $relationColumn] = explode('.', $name);
-
-            $name = Str::snake($relationName).'.'.$relationColumn;
-        }
-
         return $this->addColumn($name, $label);
     }
 

+ 24 - 6
src/Grid/Column.php

@@ -17,19 +17,19 @@ use Illuminate\Support\Traits\Macroable;
 
 /**
  * @method $this editable(bool $refresh = false)
- * @method $this switch(string $color = '')
- * @method $this switchGroup($columns = [], string $color = '')
+ * @method $this switch(string $color = '', $refresh = false)
+ * @method $this switchGroup($columns = [], string $color = '', $refresh = false)
  * @method $this image($server = '', int $width = 200, int $height = 200)
  * @method $this label($style = 'primary', int $max = null)
  * @method $this button($style = 'success');
  * @method $this link($href = '', $target = '_blank');
  * @method $this badge($style = 'primary', int $max = null);
  * @method $this progressBar($style = 'primary', $size = 'sm', $max = 100)
- * @method $this checkbox($options = [])
- * @method $this radio($options = [])
+ * @method $this checkbox($options = [], $refresh = false)
+ * @method $this radio($options = [], $refresh = false)
  * @method $this expand($callbackOrButton = null)
  * @method $this table($titles = [])
- * @method $this select($options = [])
+ * @method $this select($options = [], $refresh = false)
  * @method $this modal($title = '', $callback = null)
  * @method $this showTreeInDialog($callbackOrNodes = null)
  * @method $this qrcode($formatter = null, $width = 150, $height = 150)
@@ -186,13 +186,31 @@ class Column
      */
     public function __construct($name, $label)
     {
-        $this->name = $name;
+        $this->name = $this->formatName($name);
 
         $this->label = $this->formatLabel($label);
 
         $this->callResolving();
     }
 
+    protected function formatName($name)
+    {
+        if (! Str::contains($name, '.')) {
+            return $name;
+        }
+
+        $names = explode('.', $name);
+        $count = count($names);
+
+        foreach ($names as $i => &$name) {
+            if ($i + 1 < $count) {
+                $name = Str::snake($name);
+            }
+        }
+
+        return implode('.', $names);
+    }
+
     /**
      * Extend column displayer.
      *

+ 11 - 10
src/Grid/Displayers/Checkbox.php

@@ -7,7 +7,7 @@ use Dcat\Admin\Support\Helper;
 
 class Checkbox extends AbstractDisplayer
 {
-    public function display($options = [])
+    public function display($options = [], $refresh = false)
     {
         if ($options instanceof \Closure) {
             $options = $options->call($this, $this->row);
@@ -34,7 +34,7 @@ class Checkbox extends AbstractDisplayer
 EOT;
         }
 
-        Admin::script($this->script());
+        Admin::script($this->addScript($refresh));
 
         return <<<EOT
 <form class="form-group {$this->getElementClass()}" style="text-align:left;" data-key="{$this->getKey()}">
@@ -54,19 +54,19 @@ EOT;
         return 'grid-checkbox-'.$this->column->getName();
     }
 
-    protected function script()
+    protected function addScript($refresh)
     {
         return <<<JS
 (function () {
-    var f;
     $('form.{$this->getElementClass()}').off('submit').on('submit', function () {
         var values = $(this).find('input:checkbox:checked').map(function (_, el) {
             return $(el).val();
-        }).get(), btn = $(this).find('[type="submit"]');
-        
-        if (f) return;
-        f = 1;
+        }).get(), 
+        btn = $(this).find('[type="submit"]'),
+        reload = '{$refresh}';
         
+        if (btn.attr('loading')) return;
+        btn.attr('loading', 1);
         btn.buttonLoading();
     
         var data = {
@@ -82,12 +82,13 @@ EOT;
             data: JSON.stringify(data),
             success: function (data) {
                 btn.buttonLoading(false);
-                f = 0;
+                btn.removeAttr('loading');
                 Dcat.success(data.message);
+                reload && Dcat.reload();
             },
             error: function (a, b, c) {
                 btn.buttonLoading(false);
-                f = 0;
+                btn.removeAttr('loading');
                 Dcat.handleAjaxError(a, b, c);
             },
         });

+ 13 - 10
src/Grid/Displayers/Radio.php

@@ -6,7 +6,7 @@ use Dcat\Admin\Admin;
 
 class Radio extends AbstractDisplayer
 {
-    public function display($options = [])
+    public function display($options = [], $refresh = false)
     {
         if ($options instanceof \Closure) {
             $options = $options->call($this, $this->row);
@@ -30,7 +30,7 @@ class Radio extends AbstractDisplayer
 EOT;
         }
 
-        Admin::script($this->script());
+        Admin::script($this->addScript($refresh));
 
         return <<<EOT
 <form class="form-group {$this->getElementClass()}" style="text-align: left" data-key="{$this->getKey()}">
@@ -50,17 +50,19 @@ EOT;
         return 'grid-radio-'.$this->column->getName();
     }
 
-    protected function script()
+    protected function addScript($refresh)
     {
         return <<<JS
 (function () {
-    var f;
     $('form.{$this->getElementClass()}').on('submit', function () {
-        var value = $(this).find('input:radio:checked').val(), btn = $(this).find('[type="submit"]');
-        
-        if (f) return;
-        f = 1;
+        var value = $(this).find('input:radio:checked').val(), 
+            btn = $(this).find('[type="submit"]'),
+            reload = '{$refresh}';
         
+        if (btn.attr('loading')) {
+            return;
+        }
+        btn.attr('loading', 1);
         btn.buttonLoading();
     
         $.ajax({
@@ -73,12 +75,13 @@ EOT;
             },
             success: function (data) {
                 btn.buttonLoading(false);
-                f = 0;
+                btn.removeAttr('loading');
                 Dcat.success(data.message);
+                reload && Dcat.reload()
             },
             error: function (a, b, c) {
                 btn.buttonLoading(false);
-                f = 0;
+                btn.removeAttr('loading');
                 Dcat.handleAjaxError(a, b, c);
             },
         });

+ 6 - 4
src/Grid/Displayers/Select.php

@@ -11,13 +11,13 @@ class Select extends AbstractDisplayer
 
     protected $selector = 'grid-column-select';
 
-    public function display($options = [])
+    public function display($options = [], $refresh = false)
     {
         if ($options instanceof \Closure) {
             $options = $options->call($this, $this->row);
         }
 
-        $this->addScript();
+        $this->addScript($refresh);
 
         $optionsHtml = '';
 
@@ -40,7 +40,7 @@ EOT;
         return $this->resource().'/'.$this->getKey();
     }
 
-    protected function addScript()
+    protected function addScript($refresh)
     {
         $script = <<<JS
 $('.{$this->selector}').off('change').select2().on('change', function(){
@@ -50,7 +50,8 @@ $('.{$this->selector}').off('change').select2().on('change', function(){
         data = {
             _token: Dcat.token,
             _method: 'PUT'
-        };
+        },
+        reload = '{$refresh}';
     
     if (name.indexOf('.') === -1) {
         data[name] = value;
@@ -69,6 +70,7 @@ $('.{$this->selector}').off('change').select2().on('change', function(){
         success: function (data) {
             Dcat.NP.done();
             Dcat.success(data.message);
+            reload && Dcat.reload();
         }
     });
 });

+ 11 - 7
src/Grid/Displayers/SwitchDisplay.php

@@ -21,7 +21,7 @@ class SwitchDisplay extends AbstractDisplayer
         $this->color = Admin::color()->get($color);
     }
 
-    public function display(string $color = '')
+    public function display(string $color = '', $refresh = false)
     {
         if ($color instanceof \Closure) {
             $color->call($this->row, $this);
@@ -29,7 +29,7 @@ class SwitchDisplay extends AbstractDisplayer
             $this->color($color);
         }
 
-        $this->addScript();
+        $this->addScript($refresh);
 
         $checked = $this->value ? 'checked' : '';
         $color = $this->color ?: Admin::color()->primary();
@@ -44,20 +44,23 @@ EOF;
         return $this->resource().'/'.$this->getKey();
     }
 
-    protected function addScript()
+    protected function addScript($refresh)
     {
         Admin::script(
             <<<JS
-(function(){
-    var swt = $('.{$this->selector}'), that;
-    function init(){
+(function() {
+    var swt = $('.{$this->selector}'), 
+    that, 
+    reload = '{$refresh}';
+    function initSwitchery(){
         swt.parent().find('.switchery').remove();
         swt.each(function(k){
             that = $(this);
             new Switchery(that[0], that.data())
         })
     } 
-    init();
+    initSwitchery();
+    
     swt.off('change').change(function(e) {
         var that = $(this), 
          url = that.data('url'),
@@ -88,6 +91,7 @@ EOF;
                 Dcat.NP.done();
                 if (d.status) {
                     Dcat.success(d.message);
+                    reload && Dcat.reload();
                 } else {
                     Dcat.error(d.message);
                 }

+ 10 - 7
src/Grid/Displayers/SwitchGroup.php

@@ -9,13 +9,13 @@ class SwitchGroup extends SwitchDisplay
 {
     protected $selector = 'grid-column-switch-group';
 
-    public function display($columns = [], string $color = '')
+    public function display($columns = [], $color = '', $refresh = false)
     {
         if ($columns instanceof \Closure) {
             $columns = $columns->call($this->row, $this);
         }
 
-        $this->addScript();
+        $this->addScript($refresh);
 
         if ($color) {
             $this->color($color);
@@ -49,20 +49,22 @@ class SwitchGroup extends SwitchDisplay
 EOT;
     }
 
-    protected function addScript()
+    protected function addScript($refresh)
     {
         $script = <<<JS
 (function () {
-    var swt = $('.{$this->selector}'), that;
-    function init(){
-        swt.each(function(){
+    var swt = $('.{$this->selector}'),
+        reload = '{$refresh}', 
+        that;
+    function initSwitchery() {
+        swt.each(function() {
              that = $(this);
              that.parent().find('.switchery').remove();
              
              new Switchery(that[0], that.data())
         })
     } 
-    init();
+    initSwitchery();
     swt.off('change').change(function(e) {
         var that = $(this), 
             id = that.data('key'),
@@ -93,6 +95,7 @@ EOT;
                 Dcat.NP.done();
                  if (d.status) {
                     Dcat.success(d.message);
+                    reload && Dcat.reload()
                 } else {
                     Dcat.error(d.message);
                 }

+ 6 - 0
src/Support/Helper.php

@@ -743,6 +743,12 @@ class Helper
 
         foreach ($relations as $first => $v) {
             if (isset($input[$first])) {
+                foreach ($input[$first] as $key => $value) {
+                    if (is_array($value) && ! Arr::isAssoc($value)) {
+                        $input["$first.$key"] = $value;
+                    }
+                }
+
                 $input = array_merge($input, Arr::dot([$first => $input[$first]]));
             }
         }

+ 1 - 0
src/Widgets/Form.php

@@ -79,6 +79,7 @@ use Illuminate\Validation\Validator;
  * @method Field\Markdown       markdown($column, $label = '')
  * @method Field\Range          range($start, $end, $label = '')
  * @method Field\Color          color($column, $label = '')
+ * @method Field\ArrayField     array($column, $labelOrCallback, $callback = null)
  */
 class Form implements Renderable
 {

Некоторые файлы не были показаны из-за большого количества измененных файлов