Laravel Nova Table Metric添加删除行动作遇问题求助
Laravel Nova Table Metric 添加带输入框的删除动作方案
因为pavloniym/nova-action-buttons仅支持资源表格视图,不兼容Table Metric,这里提供三个可行的实现方案:
方案一:自定义Vue组件对接Nova原生Action系统
这个方案复用Nova自带的Action模态框和API,体验最贴近原生Nova操作:
- 创建Vue按钮组件
在resources/js/components/DeleteOrderButton.vue中编写组件:
<template> <button @click="triggerDelete" class="btn btn-danger btn-sm ml-2"> 删除订单 </button> </template> <script> export default { props: ['resourceId'], methods: { async triggerDelete() { // 加载DeleteOrder动作的配置 const actionRes = await Nova.request().get('/nova-api/orders/actions/delete-order'); const actionFields = actionRes.data.fields; // 弹出Nova原生表单模态框 const { response } = await Nova.modal( '删除订单', Nova.form(actionFields, { resourceName: 'orders', resourceId: this.resourceId, actionId: 'delete-order', }) ); if (response) { // 提交动作请求 await Nova.request().post('/nova-api/orders/actions/delete-order', { resources: [this.resourceId], ...response.data, }); // 刷新当前Metric数据 Nova.refreshMetrics(); Nova.success('订单已删除'); } } } }; </script>
- 注册组件到Nova
在app/Providers/NovaServiceProvider.php的boot方法中添加组件注册:
use Laravel\Nova\Nova; use Laravel\Nova\Events\ServingNova; public function boot() { parent::boot(); Nova::serving(function (ServingNova $event) { Nova::script('delete-order-button', public_path('js/delete-order-button.js')); }); }
- 编译组件并在Table Metric中使用
执行npm run prod编译组件,然后在你的Table Metric类中添加自定义按钮:
use Laravel\Nova\Metrics\Table; use Laravel\Nova\Http\Requests\NovaRequest; class OrdersInInvoiceWithExpireDate extends Table { public function calculate(NovaRequest $request) { return $this->count($request, Order::class) ->rows(function ($order) { return [ 'id' => $order->id, 'number' => $order->number, // 其他字段... 'actions' => implode('', [ $this->editButton($order), "<delete-order-button :resource-id=\"{$order->id}\"></delete-order-button>" ]), ]; }); } public function columns() { return [ 'id' => '订单ID', 'number' => '订单编号', // 其他列... 'actions' => '操作', ]; } // 允许渲染HTML内容 public function allowHtml() { return true; } }
方案二:基于Nova Inline Action实现(Nova 4+)
如果你的Nova版本是4.x及以上,可以用Inline Action特性,只需少量代码适配:
- 修改DeleteOrder动作类
让动作实现InlineAction接口:
use Laravel\Nova\Actions\Action; use Laravel\Nova\Actions\InlineAction; use Laravel\Nova\Fields\Textarea; use Laravel\Nova\Http\Requests\NovaRequest; class DeleteOrder extends Action implements InlineAction { public $name = '删除订单'; public function fields(NovaRequest $request) { return [ Textarea::make('备注', 'note')->required(), ]; } public function handle(NovaRequest $request, $model) { $model->delete(); \Log::info('订单删除日志', ['order_id' => $model->id, 'note' => $request->note]); return Action::message('订单已成功删除'); } public function uriKey() { return 'delete-order'; } }
- 添加按钮并绑定触发逻辑
在Table Metric的行操作中添加按钮,同时注册JS逻辑:
// Table Metric的rows方法中 'actions' => implode('', [ $this->editButton($order), "<button class=\"inline-delete-btn btn btn-danger btn-sm ml-2\" data-id=\"{$order->id}\">删除订单</button>" ]),
创建resources/js/nova-delete-action.js并注册到Nova:
document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.inline-delete-btn').forEach(btn => { btn.addEventListener('click', async (e) => { e.preventDefault(); const orderId = btn.dataset.id; // 加载动作配置并弹出模态框 const actionRes = await Nova.request().get('/nova-api/orders/actions/delete-order'); const { response } = await Nova.modal( actionRes.data.name, Nova.form(actionRes.data.fields, { resourceName: 'orders', resourceId: orderId, actionId: 'delete-order', }) ); if (response) { await Nova.request().post('/nova-api/orders/actions/delete-order', { resources: [orderId], ...response.data, }); Nova.refreshMetrics(); } }); }); });
在NovaServiceProvider中注册该JS文件:
Nova::script('nova-delete-action', public_path('js/nova-delete-action.js'));
方案三:纯自定义AJAX删除逻辑
完全脱离Nova的Action系统,自己实现模态框和删除接口,灵活性最高:
- 创建删除接口
在routes/nova.php中添加路由:
use App\Http\Controllers\Nova\DeleteOrderController; Route::post('/delete-order', [DeleteOrderController::class, '__invoke'])->name('nova.delete-order');
创建控制器app/Http/Controllers/Nova/DeleteOrderController.php:
use App\Models\Order; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; class DeleteOrderController extends Controller { public function __invoke(Request $request) { $request->validate([ 'order_id' => 'required|exists:orders,id', 'note' => 'required|string', ]); $order = Order::findOrFail($request->order_id); $order->delete(); Log::info('订单删除记录', [ 'order_id' => $order->id, 'note' => $request->note, 'operator' => auth()->user()->name, ]); return response()->json(['success' => true, 'message' => '订单已删除']); } }
- 添加按钮和模态框
在Table Metric的行操作中添加按钮:
'actions' => implode('', [ $this->editButton($order), "<button class=\"custom-delete-btn btn btn-danger btn-sm ml-2\" data-id=\"{$order->id}\">删除订单</button>" ]),
在Nova的自定义布局或通过JS注入模态框:
<div id="delete-modal" class="modal fade" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">确认删除订单</h5> <button type="button" class="close" data-dismiss="modal">×</button> </div> <div class="modal-body"> <textarea id="delete-note" class="form-control" placeholder="请输入删除备注" required></textarea> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button> <button type="button" class="btn btn-danger" id="confirm-delete">确认删除</button> </div> </div> </div> </div> <script> let currentOrderId = null; document.addEventListener('DOMContentLoaded', () => { // 打开模态框 document.querySelectorAll('.custom-delete-btn').forEach(btn => { btn.addEventListener('click', () => { currentOrderId = btn.dataset.id; $('#delete-modal').modal('show'); }); }); // 提交删除 document.getElementById('confirm-delete').addEventListener('click', async () => { const note = document.getElementById('delete-note').value.trim(); if (!note) return; try { const res = await fetch('/nova/delete-order', { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content, 'Content-Type': 'application/json', }, body: JSON.stringify({ order_id: currentOrderId, note: note, }), }); const data = await res.json(); if (data.success) { $('#delete-modal').modal('hide'); Nova.refreshMetrics(); Nova.success(data.message); } else { Nova.error('删除失败,请重试'); } } catch (err) { Nova.error('请求出错,请检查网络'); } }); }); </script>
将上述HTML和JS编译后注册到Nova即可。
内容的提问来源于stack exchange,提问作者mstdmstd
相关产品推荐
相关产品推荐

