求助:Laravel Nova 4表单添加自定义按钮实现保存后复制记录
Laravel Nova 4 添加「保存并复制」自定义按钮方案
以下是实现表单底部自定义按钮,保存当前记录后自动填充数据到新创建表单的具体步骤:
步骤1:创建前端自定义按钮组件
在项目的 resources/js/components 目录下新建 SaveAndDuplicateButton.vue 文件,实现保存后跳转并预填数据的逻辑:
<template> <NovaButton type="primary" :disabled="form.processing" @click="handleSaveAndDuplicate" > 保存并复制 </NovaButton> </template> <script setup> import { useForm } from '@nova-ui/framework' const form = useForm() async function handleSaveAndDuplicate() { // 先提交保存当前记录 await form.submit() // 过滤无需复制的系统字段 const payload = Object.fromEntries( Object.entries(form.value).filter(([key]) => !['id', 'created_at', 'updated_at', 'deleted_at'].includes(key)) ) // 生成带预填参数的创建页面链接并跳转 const queryString = new URLSearchParams(payload).toString() window.location.href = `/nova/resources/${form.resourceName}/create?${queryString}` } </script>
在 resources/js/app.js 中注册该组件:
import SaveAndDuplicateButton from './components/SaveAndDuplicateButton' Nova.booting((app) => { app.component('save-and-duplicate-button', SaveAndDuplicateButton) })
运行 npm run dev 编译前端资源。
步骤2:在Resource中添加自定义按钮
打开对应的Nova Resource文件(如 app/Nova/YourResource.php),重写 formActions 方法,将自定义按钮添加到表单操作栏:
use Laravel\Nova\Actions\Action; use Laravel\Nova\Http\Requests\NovaRequest; class YourResource extends Resource { // ... 其他配置代码 public function formActions(NovaRequest $request) { return [ // 保留默认保存按钮 Action::make('保存') ->submit('save'), // 添加自定义「保存并复制」按钮 Action::make('保存并复制') ->component('save-and-duplicate-button'), // 可选:保留默认「保存并新增」按钮 Action::make('保存并新增') ->submit('saveAndContinue'), ]; } }
步骤3:处理特殊字段(可选)
Nova默认会自动匹配URL参数与表单字段名完成填充,但部分特殊字段需要额外处理:
- 关联字段:直接传递关联ID(如
category_id=1)即可自动选中对应模型; - 文件字段:无法通过URL参数传递,会自动留空,需用户重新上传;
- 敏感字段:在前端过滤逻辑中添加字段名(如
password),避免复制敏感数据。
可选优化:后端处理复制逻辑(更可靠)
如果需要处理复杂的复制规则(如关联模型复制、字段默认值修改),可以通过后端接口实现:
- 在
routes/web.php中添加Nova专用路由:
use Illuminate\Support\Facades\Route; use Laravel\Nova\Http\Requests\NovaRequest; Route::post('/nova/resources/{resource}/{id}/duplicate', function (NovaRequest $request, $resource, $id) { $model = $request->findModelOrFail($id); // 复制模型并过滤系统字段 $duplicate = $model->replicate([ 'created_at', 'updated_at', 'deleted_at' // 可添加其他无需复制的字段 ]); // 可选:修改复制后的字段默认值 // $duplicate->status = 'draft'; // 生成预填参数并跳转至创建页面 $query = http_build_query($duplicate->toArray()); return redirect()->route('nova.pages.create', [ 'resource' => $resource, 'query' => $query, ]); })->middleware(['nova'])->name('nova.resources.duplicate');
- 修改前端按钮的点击逻辑,调用后端接口:
async function handleSaveAndDuplicate() { await form.submit() if (form.mode.value === 'update') { // 更新页面调用后端复制接口 const response = await fetch(`/nova/resources/${form.resourceName}/${form.value.id}/duplicate`, { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content, 'Accept': 'application/json', }, }) const data = await response.json() window.location.href = data.redirectUrl } else { // 创建页面沿用前端逻辑 const payload = Object.fromEntries( Object.entries(form.value).filter(([key]) => !['id', 'created_at', 'updated_at', 'deleted_at'].includes(key)) ) const queryString = new URLSearchParams(payload).toString() window.location.href = `/nova/resources/${form.resourceName}/create?${queryString}` } }
内容的提问来源于stack exchange,提问作者Eric K
相关产品推荐
相关产品推荐

