跳转至

在 Filament v3.3 中,在非后台页面使用 Forms 功能有几种方式。以下是详细的实现方法:

1. 使用 Livewire 组件方式(推荐)

创建 Livewire 组件

php artisan make:livewire ContactForm

实现 Livewire 组件

<?php

namespace App\Http\Livewire;

use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;
use Livewire\WithFileUploads;

class ContactForm extends Component implements HasForms
{
    use InteractsWithForms;
    use WithFileUploads;

    public $name;
    public $email;
    public $phone;
    public $subject;
    public $message;
    public $attachment;
    public $agree_terms = false;

    public function mount(): void
    {
        $this->form->fill();
    }

    public function getFormSchema(): array
    {
        return [
            TextInput::make('name')
                ->label('姓名')
                ->required()
                ->maxLength(255)
                ->placeholder('请输入您的姓名'),

            TextInput::make('email')
                ->label('邮箱地址')
                ->email()
                ->required()
                ->placeholder('example@email.com'),

            TextInput::make('phone')
                ->label('联系电话')
                ->tel()
                ->placeholder('请输入您的手机号'),

            Select::make('subject')
                ->label('咨询主题')
                ->options([
                    'product' => '产品咨询',
                    'technical' => '技术支持',
                    'cooperation' => '合作洽谈',
                    'complaint' => '投诉建议',
                    'other' => '其他',
                ])
                ->required()
                ->native(false),

            Textarea::make('message')
                ->label('详细内容')
                ->required()
                ->rows(5)
                ->placeholder('请详细描述您的问题或需求...'),

            FileUpload::make('attachment')
                ->label('附件上传')
                ->acceptedFileTypes(['application/pdf', 'image/*'])
                ->maxSize(5120)
                ->directory('contact-attachments')
                ->preserveFilenames(),

            Checkbox::make('agree_terms')
                ->label('我同意相关服务条款')
                ->required(),
        ];
    }

    public function submit(): void
    {
        $data = $this->form->getState();

        // 处理表单提交逻辑
        // 例如保存到数据库、发送邮件等

        // 示例:保存数据
        // Contact::create($data);

        // 显示成功消息
        session()->flash('success', '表单提交成功!我们会尽快与您联系。');

        // 重置表单
        $this->form->fill();
    }

    public function render()
    {
        return view('livewire.contact-form');
    }
}

创建 Livewire 视图

<!-- resources/views/livewire/contact-form.blade.php -->
<div class="max-w-2xl mx-auto p-6 bg-white rounded-lg shadow-md">
    <h2 class="text-2xl font-bold mb-6 text-gray-800">联系我们</h2>

    <form wire:submit.prevent="submit" class="space-y-6">
        {{ $this->form }}

        <div class="flex justify-end">
            <button 
                type="submit" 
                class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
            >
                提交表单
            </button>
        </div>
    </form>

    @if (session()->has('success'))
        <div class="mt-4 p-4 bg-green-100 border border-green-400 text-green-700 rounded">
            {{ session('success') }}
        </div>
    @endif
</div>

2. 在普通 Blade 视图中使用

创建服务类

<?php

namespace App\Services;

use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Form;

class ContactFormService
{
    public static function make(): Form
    {
        return Form::make()
            ->schema([
                TextInput::make('name')
                    ->label('姓名')
                    ->required(),
                TextInput::make('email')
                    ->label('邮箱')
                    ->email()
                    ->required(),
                Select::make('department')
                    ->label('部门')
                    ->options([
                        'sales' => '销售部',
                        'support' => '技术支持',
                        'billing' => '财务部',
                    ]),
                Textarea::make('message')
                    ->label('留言')
                    ->rows(4),
            ]);
    }
}

在控制器中使用

<?php

namespace App\Http\Controllers;

use App\Services\ContactFormService;
use Illuminate\Http\Request;

class ContactController extends Controller
{
    public function create()
    {
        $form = ContactFormService::make();

        return view('contact', compact('form'));
    }

    public function store(Request $request)
    {
        $form = ContactFormService::make();

        try {
            $data = $form->getState($request->all());

            // 处理数据
            // Contact::create($data);

            return redirect()->back()->with('success', '提交成功!');

        } catch (\Exception $e) {
            return redirect()->back()->with('error', '提交失败:' . $e->getMessage());
        }
    }
}

Blade 视图

<!DOCTYPE html>
<html>
<head>
    <title>联系我们</title>
    <!-- 引入 Filament 样式 -->
    @filamentStyles
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-50">
    <div class="min-h-screen py-12">
        <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="max-w-3xl mx-auto">
                <div class="bg-white rounded-lg shadow-md p-6">
                    <h1 class="text-3xl font-bold text-gray-900 mb-8">联系我们</h1>

                    <form method="POST" action="{{ route('contact.store') }}">
                        @csrf

                        <div class="space-y-6">
                            {{ $form }}
                        </div>

                        <div class="mt-8">
                            <button type="submit" class="w-full py-3 px-4 bg-blue-600 text-white font-semibold rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
                                提交信息
                            </button>
                        </div>
                    </form>

                    @if (session('success'))
                        <div class="mt-4 p-4 bg-green-100 border border-green-400 text-green-700 rounded">
                            {{ session('success') }}
                        </div>
                    @endif

                    @if (session('error'))
                        <div class="mt-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded">
                            {{ session('error') }}
                        </div>
                    @endif
                </div>
            </div>
        </div>
    </div>

    <!-- 引入 Filament 脚本 -->
    @filamentScripts
</body>
</html>

3. 配置路由

// routes/web.php
use App\Http\Livewire\ContactForm;
use App\Http\Controllers\ContactController;

// 使用 Livewire 组件
Route::get('/contact-livewire', ContactForm::class)->name('contact.livewire');

// 使用传统控制器方式
Route::get('/contact', [ContactController::class, 'create'])->name('contact.create');
Route::post('/contact', [ContactController::class, 'store'])->name('contact.store');

4. 自定义样式和配置

发布 Filament 资源(如果需要自定义)

php artisan filament:publish --assets

自定义 CSS(可选)

/* resources/css/filament-frontend.css */
.filament-forms-component {
    margin-bottom: 1.5rem;
}

.filament-forms-label {
    font-weight: 600;
    margin-bottom: 0.5rem;
    display: block;
}

5. 高级功能示例

带条件显示的字段

public function getFormSchema(): array
{
    return [
        Select::make('contact_type')
            ->label('联系类型')
            ->options([
                'individual' => '个人',
                'company' => '企业',
            ])
            ->reactive(),

        TextInput::make('company_name')
            ->label('公司名称')
            ->visible(fn ($get) => $get('contact_type') === 'company'),

        TextInput::make('company_size')
            ->label('公司规模')
            ->visible(fn ($get) => $get('contact_type') === 'company'),
    ];
}

表单验证规则

TextInput::make('email')
    ->label('邮箱')
    ->email()
    ->required()
    ->rules(['email:rfc,dns']),

TextInput::make('phone')
    ->label('手机号')
    ->tel()
    ->rules(['regex:/^1[3-9]\d{9}$/']),

注意事项

  1. 确保安装依赖

    composer require filament/filament:"^3.3"
    

  2. 样式冲突:Filament 使用 Tailwind CSS,确保与现有样式兼容

  3. 文件上传:使用 WithFileUploads trait 并配置正确的磁盘

  4. 性能考虑:Filament Forms 会加载较多资源,考虑按需加载

这种方式让你可以在任何 Laravel 应用中使用 Filament v3.3 的强大表单功能,而不仅限于后台管理界面。