From 875c3a16d7f7fe59ad86a903a073e4e10fa21b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=99=AF=E7=AB=8B?= Date: Thu, 21 May 2026 00:15:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(form):=20=E5=A2=9E=E5=8A=A0=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=A0=85=E6=A0=BC=E5=B8=83=E5=B1=80=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 FormModules::grid 与 gridColumn,用统一方法生成 1 到 4 列的标准表单栅格,避免各业务表单重复拼接 layui 栅格类名。 在表单渲染壳层中注入标准样式,统一栅格列宽、字段间距、单行说明省略和自动补全下拉层样式,保证弹窗与页面模式展示一致。 补充 FormBuilderTest 覆盖可复用栅格布局、nowrap 说明文案和标准样式输出,防止后续表单布局能力回退。 --- .../src/builder/form/module/FormModules.php | 47 +++++++++++++++++++ .../builder/form/render/FormShellRenderer.php | 28 +++++++++++ .../think-library/tests/FormBuilderTest.php | 33 +++++++++++++ 3 files changed, 108 insertions(+) diff --git a/plugin/think-library/src/builder/form/module/FormModules.php b/plugin/think-library/src/builder/form/module/FormModules.php index e3f147f28..e597dc228 100644 --- a/plugin/think-library/src/builder/form/module/FormModules.php +++ b/plugin/think-library/src/builder/form/module/FormModules.php @@ -13,6 +13,48 @@ use think\admin\builder\form\FormNode; */ class FormModules { + /** + * 标准表单栅格容器. + */ + public static function grid(FormNode $parent, int $columns = 2, string|array $class = '', int $space = 15): FormNode + { + $columns = self::normalizeGridColumns($columns); + $space = max(0, min(30, $space)); + $node = $parent->div()->class([ + 'layui-row', + "layui-col-space{$space}", + 'ta-form-grid', + "ta-form-grid-{$columns}", + ]); + if ($class !== '' && $class !== []) { + $node->class($class); + } + return $node; + } + + /** + * 标准表单栅格列. + */ + public static function gridColumn(FormNode $parent, int $columns = 2, string|array $class = ''): FormNode + { + $columns = self::normalizeGridColumns($columns); + $span = match ($columns) { + 1 => 12, + 2 => 6, + 3 => 4, + default => 3, + }; + + $node = $parent->div()->class([ + "layui-col-xs{$span}", + 'ta-form-grid-col', + ]); + if ($class !== '' && $class !== []) { + $node->class($class); + } + return $node; + } + /** * @param array $config */ @@ -84,4 +126,9 @@ class FormModules { return htmlentities($content, ENT_QUOTES, 'UTF-8'); } + + private static function normalizeGridColumns(int $columns): int + { + return max(1, min(4, $columns)); + } } diff --git a/plugin/think-library/src/builder/form/render/FormShellRenderer.php b/plugin/think-library/src/builder/form/render/FormShellRenderer.php index cbe7162ad..722b60ec2 100644 --- a/plugin/think-library/src/builder/form/render/FormShellRenderer.php +++ b/plugin/think-library/src/builder/form/render/FormShellRenderer.php @@ -39,6 +39,7 @@ class FormShellRenderer $html = sprintf('
', $context->attrs($attrs)); $html .= "\n\t" . sprintf('
', $context->attrs($bodyAttrs)); + $html .= "\n\t\t" . $this->renderStandardStyle(); if (count($content) > 0) { $html .= $context->renderChildren($content); @@ -76,6 +77,7 @@ class FormShellRenderer $header = (new PageHeaderRenderer())->render(strval($schema['title'] ?? ''), $headerButtons); $form = sprintf('', $context->attrs($attrs)); $form .= "\n\t\t\t\t" . sprintf('
', $context->attrs($bodyAttrs)); + $form .= "\n\t\t\t\t\t" . $this->renderStandardStyle(); if (count($content) > 0) { $form .= "\n\t\t\t\t\t" . $context->renderChildren($content); @@ -116,4 +118,30 @@ class FormShellRenderer $html .= "\n\t" . '
'; return $html . "\n
"; } + + private function renderStandardStyle(): string + { + return <<<'HTML' + +HTML; + } } diff --git a/plugin/think-library/tests/FormBuilderTest.php b/plugin/think-library/tests/FormBuilderTest.php index e00cc1757..e07a0befb 100644 --- a/plugin/think-library/tests/FormBuilderTest.php +++ b/plugin/think-library/tests/FormBuilderTest.php @@ -25,6 +25,7 @@ use think\admin\Controller; use think\admin\builder\form\FormBuilder; use think\admin\builder\form\FormComponents; use think\admin\builder\form\FormChoiceField; +use think\admin\builder\form\module\FormModules; use think\admin\builder\form\FormSelectField; use think\admin\builder\form\FormTextField; use think\admin\builder\form\FormUploadField; @@ -348,6 +349,38 @@ class FormBuilderTest extends TestCase $this->assertStringContainsString('data-builder-modules=', $html); } + public function testFormModulesCanRenderReusableGridLayout(): void + { + $builder = $this->newBuilder(); + $builder->define(function ($form) { + $form->class('ta-form-nowrap'); + FormModules::section($form, [ + 'title' => '布局', + 'description' => '描述信息保持单行显示。', + ], function ($section) { + $grid = FormModules::grid($section, 3, 'profile-grid'); + FormModules::gridColumn($grid, 3)->fields(function ($fields) { + $fields->text('nickname', '用户名称', 'Nickname', true, '单行说明'); + }); + FormModules::gridColumn($grid, 3)->fields(function ($fields) { + $fields->text('email', '联系邮箱', 'Email'); + }); + FormModules::gridColumn($grid, 3)->fields(function ($fields) { + $fields->text('phone', '联系电话', 'Phone'); + }); + }); + })->build(); + + $html = $this->invokePrivate($builder, '_buildFormModal'); + + $this->assertStringContainsString('data-form-builder-standard-style', $html); + $this->assertStringContainsString('ta-form-nowrap', $html); + $this->assertStringContainsString('layui-row layui-col-space15 ta-form-grid ta-form-grid-3 profile-grid', $html); + $this->assertStringContainsString('layui-col-xs4 ta-form-grid-col', $html); + $this->assertStringContainsString('width:33.333333%!important', $html); + $this->assertStringContainsString('white-space:nowrap', $html); + } + public function testPageModeCanRenderTitleAndDefaultPadding(): void { $builder = $this->newBuilder('form', 'page');