瀏覽代碼

:hammer: 表单block布局重构,支持一行多列以及嵌套其他类型布局

jqh 4 年之前
父節點
當前提交
26210f64d2

+ 1 - 1
resources/assets/dcat/sass/sweetalert/sweetalert2.scss

@@ -3,7 +3,7 @@
 }
 
 .swal2-actions .btn {
-  padding: 0.7rem 1.5rem !important;;
+  padding: 0.5rem 1.5rem !important;;
 }
 
 .swal2-container {

+ 1 - 1
resources/views/form/display.blade.php

@@ -1,4 +1,4 @@
-<div class="{{$viewClass['form-group']}}">
+<div class="{{$viewClass['form-group']}}" style="margin-top: .3rem">
     <label class="{{$viewClass['label']}} control-label">{!! $label !!}</label>
     <div class="{{$viewClass['field']}}">
         <div class="box box-solid box-default no-margin">

+ 2 - 3
resources/views/widgets/form.blade.php

@@ -1,5 +1,5 @@
 {!! $start !!}
-    <div class="box-body fields-group p-0 pt-1">
+    <div class="box-body fields-group pl-0 pr-0 pt-1" style="padding: 0 0 .5rem">
         @if(! $tabObj->isEmpty())
             @include('admin::form.tab', compact('tabObj'))
 
@@ -31,7 +31,6 @@
         @endif
     </div>
 
-    <!-- /.box-body -->
     @if($buttons['submit'] || $buttons['reset'])
     <div class="box-footer row" style="display: flex">
         <div class="col-md-2"> &nbsp;</div>
@@ -49,7 +48,7 @@
     @endif
 {!! $end !!}
 
-@if(! empty($elementId))
+@if(! empty($ajax))
 <script>
     $('#{{ $elementId }}').form({
         validate: true,

+ 7 - 18
src/Form.php

@@ -1053,7 +1053,9 @@ class Form implements Renderable
      */
     public function ignore($fields)
     {
-        $this->ignored = array_merge($this->ignored, (array) $fields);
+        $this->ignored = Arr::flatten(
+            array_merge($this->ignored, (array) $fields)
+        );
 
         return $this;
     }
@@ -1623,11 +1625,10 @@ class Form implements Renderable
      */
     public function block(int $width, \Closure $callback)
     {
-        $layout = $this->builder->layout();
-
-        $callback($form = $layout->form());
-
-        $layout->column($width, $form);
+        $this
+            ->builder
+            ->layout()
+            ->block($width, $callback);
 
         return $this;
     }
@@ -1647,18 +1648,6 @@ class Form implements Renderable
         return $this;
     }
 
-    /**
-     * @param int $width
-     *
-     * @return $this
-     */
-    public function setDefaultBlockWidth(int $width)
-    {
-        $this->builder->setDefaultBlockWidth($width);
-
-        return $this;
-    }
-
     /**
      * @return $this
      */

+ 79 - 12
src/Form/BlockForm.php

@@ -2,10 +2,18 @@
 
 namespace Dcat\Admin\Form;
 
+use Dcat\Admin\Exception\RuntimeException;
 use Dcat\Admin\Form;
 use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Widgets\Form as WidgetForm;
 
+/**
+ * Class BlockForm
+ *
+ * @package Dcat\Admin\Form
+ *
+ * @mixin Form
+ */
 class BlockForm extends WidgetForm
 {
     /**
@@ -23,6 +31,11 @@ class BlockForm extends WidgetForm
      */
     protected $title;
 
+    /**
+     * @var \Dcat\Admin\Layout\Row
+     */
+    public $layoutRow;
+
     public function __construct(Form $form)
     {
         $this->form = $form;
@@ -33,6 +46,13 @@ class BlockForm extends WidgetForm
         $this->initFormAttributes();
     }
 
+    /**
+     * 设置标题.
+     *
+     * @param string $title
+     *
+     * @return $this
+     */
     public function title($title)
     {
         $this->title = $title;
@@ -41,17 +61,50 @@ class BlockForm extends WidgetForm
     }
 
     /**
-     * Add a form field to form.
+     * 显示底部内容.
      *
-     * @param Field $field
+     * @return $this
+     */
+    public function showFooter()
+    {
+        $this->ajax(true);
+        $this->disableSubmitButton(false);
+        $this->disableResetButton(false);
+
+        return $this;
+    }
+
+    /**
+     * 在当前列增加一块表单.
+     *
+     * @param \Closure $callback
      *
      * @return $this
      */
+    public function next(\Closure $callback)
+    {
+        $this->layoutRow->column(
+            12,
+            $form = $this->form
+                ->builder()
+                ->layout()
+                ->form()
+        );
+
+        $callback($form);
+
+        return $this;
+    }
+
     public function pushField(Field $field)
     {
         $this->form->builder()->fields()->push($field);
         $this->fields->push($field);
 
+        if ($this->layout()->hasColumns()) {
+            $this->layout()->addField($field);
+        }
+
         $field->attribute(Builder::BUILD_IGNORE, true);
 
         $field->setForm($this->form);
@@ -64,22 +117,17 @@ class BlockForm extends WidgetForm
 
     public function render()
     {
-        $view = Helper::render(parent::render());
+        $class = $this->title ? '' : 'pt-1';
 
-        $style = $this->title ? '' : 'padding-top: 13px';
+        $view = parent::render();
 
         return <<<HTML
-<div class='box' style="{$style}">
-    {$this->renderHeader()} 
-    {$view}
+<div class='box {$class} mb-1'>
+    {$this->renderHeader()} {$view}
 </div>
 HTML;
     }
 
-    public function fillFields(array $data)
-    {
-    }
-
     protected function renderHeader()
     {
         if (! $this->title) {
@@ -87,9 +135,28 @@ HTML;
         }
 
         return <<<HTML
-<div class="box-header with-border mb-1">
+<div class="box-header with-border" style="margin-bottom: .5rem">
     <h3 class="box-title">{$this->title}</h3>
 </div>
 HTML;
     }
+
+    public function getKey()
+    {
+        return $this->form->getKey();
+    }
+
+    public function __call($method, $arguments)
+    {
+        try {
+            return parent::__call($method, $arguments);
+        } catch (RuntimeException $e) {
+            return $this->form->$method($arguments);
+        }
+    }
+
+    public function fillFields(array $data)
+    {
+    }
+
 }

+ 19 - 30
src/Form/Builder.php

@@ -109,21 +109,11 @@ class Builder
      */
     protected $title;
 
-    /**
-     * @var BlockForm[]
-     */
-    protected $multipleForms = [];
-
     /**
      * @var Layout
      */
     protected $layout;
 
-    /**
-     * @var int
-     */
-    protected $defaultBlockWidth = 12;
-
     /**
      * @var string
      */
@@ -214,20 +204,6 @@ class Builder
         return $this;
     }
 
-    /**
-     * @param BlockForm $form
-     */
-    public function addForm(BlockForm $form)
-    {
-        $this->multipleForms[] = $form;
-
-        $form->disableResetButton();
-        $form->disableSubmitButton();
-        $form->disableFormTag();
-
-        return $this;
-    }
-
     /**
      * Get form tools instance.
      *
@@ -885,19 +861,32 @@ class Builder
         if ($this->layout->hasColumns()) {
             $content = $this->doWrap(view($this->view, $data));
         } else {
-            $this->layout->prepend(
-                $this->defaultBlockWidth,
-                $this->doWrap(view($this->view, $data))
-            );
+            if (! $this->layout->hasBlocks()) {
+                $this->layout->prepend(
+                    12,
+                    $this->doWrap(view($this->view, $data))
+                );
+            }
 
             $content = $this->layout->build();
         }
 
         return <<<EOF
-{$open} {$content} {$this->close()}
+{$open} {$content} {$this->renderHiddenFields()} {$this->close()}
 EOF;
     }
 
+    protected function renderHiddenFields()
+    {
+        $html = '';
+
+        foreach($this->hiddenFields() as $field) {
+            $html .= $field->render();
+        }
+
+        return $html;
+    }
+
     /**
      * @param Renderable $view
      *
@@ -923,7 +912,7 @@ EOF;
             <<<JS
 $('#{$this->getElementId()}').form({
     validate: true,
-     confirm: {$confirm},
+    confirm: {$confirm},
 });
 JS
         );

+ 1 - 1
src/Form/Field/File.php

@@ -173,7 +173,7 @@ class File extends Field implements UploadFieldInterface
     protected function formatValue()
     {
         if ($this->value !== null) {
-            $this->value = implode(',', $this->value);
+            $this->value = implode(',', Helper::array($this->value));
         } elseif (is_array($this->default)) {
             $this->default = implode(',', $this->default);
         }

+ 51 - 9
src/Form/Layout.php

@@ -23,6 +23,8 @@ class Layout
      */
     protected $currentFields = [];
 
+    protected $hasBlock = false;
+
     /**
      * @var bool
      */
@@ -38,26 +40,31 @@ class Layout
         $this->currentFields[] = $field;
     }
 
+    public function hasBlocks()
+    {
+        return $this->hasBlock;
+    }
+
     public function hasColumns()
     {
         return $this->hasColumn;
     }
 
     /**
+     * 列布局.
+     *
      * @param int   $width   1~12
      * @param mixed $content
      */
     public function onlyColumn($width, $content)
     {
-        $width = $width < 1 ? round(12 * $width) : $width;
+        $width = (int) ($width < 1 ? round(12 * $width) : $width);
 
         $this->hasColumn = true;
 
-        $this->currentFields = [];
-
-        $column = new Column($content, $width);
+        $this->resetCurrentFields();
 
-        $this->columns[] = $column;
+        $column = $this->column($width, $content);
 
         foreach ($this->currentFields as $field) {
             $column->append($field);
@@ -65,14 +72,41 @@ class Layout
     }
 
     /**
+     * 增加列.
+     *
      * @param int   $width   1~12
      * @param mixed $content
+     *
+     * @return Column
+     */
+    public function column(int $width, $content)
+    {
+        return $this->columns[] = new Column($content, $width);
+    }
+
+    /**
+     * block布局.
+     *
+     * @param int $width
+     * @param \Closure $callback
      */
-    public function column($width, $content)
+    public function block(int $width, \Closure $callback)
     {
-        $width = $width < 1 ? round(12 * $width) : $width;
+        $this->hasBlock = true;
+
+        $this->column($width, function (Column $column) use ($callback) {
+            $this->form->layoutColumn = $column;
+
+            $column->row(function (\Dcat\Admin\Layout\Row $row) use ($callback) {
+                $form = $this->form();
 
-        $this->columns[] = new Column($content, $width);
+                $form->layoutRow = $row;
+
+                $row->column(12, $form);
+
+                $callback($form);
+            });
+        });
     }
 
     /**
@@ -95,7 +129,10 @@ class Layout
     {
         $form = new Form\BlockForm($this->form);
 
-        $this->form->builder()->addForm($form);
+        $form->disableResetButton();
+        $form->disableSubmitButton();
+        $form->disableFormTag();
+        $form->ajax(false);
 
         if ($callback) {
             $callback($form);
@@ -119,4 +156,9 @@ class Layout
 
         return $html.'</div>';
     }
+
+    protected function resetCurrentFields()
+    {
+        $this->currentFields = [];
+    }
 }

+ 7 - 0
src/Layout/Column.php

@@ -27,6 +27,8 @@ class Column implements Renderable
      */
     public function __construct($content, $width = 12)
     {
+        $width = $this->normalizeWidth($width);
+
         if ($content instanceof \Closure) {
             call_user_func($content, $this);
         } else {
@@ -46,6 +48,11 @@ class Column implements Renderable
         }
     }
 
+    protected function normalizeWidth($width)
+    {
+        return (int) ($width < 1 ? round(12 * $width) : $width);
+    }
+
     /**
      * Append content to column.
      *

+ 5 - 3
src/Layout/Row.php

@@ -19,7 +19,11 @@ class Row implements Renderable
     public function __construct($content = '')
     {
         if (! empty($content)) {
-            $this->column(12, $content);
+            if ($content instanceof Column) {
+                $this->addColumn($content);
+            } else {
+                $this->column(12, $content);
+            }
         }
     }
 
@@ -31,8 +35,6 @@ class Row implements Renderable
      */
     public function column($width, $content)
     {
-        $width = $width < 1 ? round(12 * $width) : $width;
-
         $column = new Column($content, $width);
 
         $this->addColumn($column);

+ 28 - 19
src/Widgets/Form.php

@@ -168,8 +168,6 @@ class Form implements Renderable
      */
     protected $confirm = [];
 
-    protected $hasColumns = false;
-
     /**
      * Form constructor.
      *
@@ -394,8 +392,6 @@ class Form implements Renderable
             $callback($this);
         });
 
-        $this->hasColumns = true;
-
         return $this;
     }
 
@@ -479,11 +475,13 @@ class Form implements Renderable
     /**
      * Disable reset button.
      *
+     * @param bool $value
+     *
      * @return $this
      */
-    public function disableResetButton()
+    public function disableResetButton(bool $value = true)
     {
-        $this->buttons['reset'] = false;
+        $this->buttons['reset'] = ! $value;
 
         return $this;
     }
@@ -491,11 +489,13 @@ class Form implements Renderable
     /**
      * Disable submit button.
      *
+     * @param bool $value
+     *
      * @return $this
      */
-    public function disableSubmitButton()
+    public function disableSubmitButton(bool $value = true)
     {
-        $this->buttons['submit'] = false;
+        $this->buttons['submit'] = ! $value;
 
         return $this;
     }
@@ -551,8 +551,8 @@ class Form implements Renderable
     public function pushField(Field $field)
     {
         $this->fields->push($field);
-        if ($this->layout) {
-            $this->layout->addField($field);
+        if ($this->layout()->hasColumns()) {
+            $this->layout()->addField($field);
         }
 
         $field->setForm($this);
@@ -588,13 +588,15 @@ class Form implements Renderable
         $this->fillFields($this->model()->toArray());
 
         return array_merge([
-            'start'   => $this->open(),
-            'end'     => $this->close(),
-            'fields'  => $this->fields,
-            'method'  => $this->getHtmlAttribute('method'),
-            'buttons' => $this->buttons,
-            'rows'    => $this->rows(),
-            'layout'  => $this->layout(),
+            'start'     => $this->open(),
+            'end'       => $this->close(),
+            'fields'    => $this->fields,
+            'method'    => $this->getHtmlAttribute('method'),
+            'buttons'   => $this->buttons,
+            'rows'      => $this->rows(),
+            'layout'    => $this->layout(),
+            'elementId' => $this->getElementId(),
+            'ajax'      => $this->useAjaxSubmit,
         ], $this->variables);
     }
 
@@ -617,6 +619,10 @@ class Form implements Renderable
      */
     protected function open()
     {
+        if (! $this->useFormTag) {
+            return;
+        }
+
         return <<<HTML
 <form {$this->formatHtmlAttributes()}>
 HTML;
@@ -627,6 +633,10 @@ HTML;
      */
     protected function close()
     {
+        if (! $this->useFormTag) {
+            return;
+        }
+
         return '</form>';
     }
 
@@ -778,7 +788,7 @@ HTML;
                 }
             };
 
-            $this->hasColumns ? $this->column(1, $addHiddenFields) : $addHiddenFields();
+            $this->layout()->hasColumns() ? $this->column(1, $addHiddenFields) : $addHiddenFields();
         }
     }
 
@@ -795,7 +805,6 @@ HTML;
 
         if ($this->allowAjaxSubmit()) {
             $this->addVariables([
-                'elementId'   => $this->getElementId(),
                 'confirm'     => $this->confirm,
                 'savedScript' => $this->savedScript(),
                 'errorScript' => $this->errorScript(),