Laravel Nova中创建发票创建视图资源的技术指导请求
实现Nova 4中Invoice资源的动态发票项功能
1. 前置准备(若未完成)
如果还没有创建发票项模型,先执行以下命令生成模型和迁移文件:
php artisan make:model InvoiceItem -m
在InvoiceItem的迁移文件中添加字段(示例):
Schema::create('invoice_items', function (Blueprint $table) { $table->id(); $table->foreignId('invoice_id')->constrained()->cascadeOnDelete(); $table->foreignId('product_id')->constrained(); $table->integer('quantity'); $table->decimal('unit_price', 10, 2); $table->timestamps(); });
执行迁移:
php artisan migrate
2. 生成Nova资源
生成Invoice和InvoiceItem对应的Nova资源:
php artisan nova:resource Invoice php artisan nova:resource InvoiceItem
3. 配置Invoice资源核心字段
在app/Nova/Invoice.php中配置基础字段和动态发票项关联:
use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\Date; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Number; use Laravel\Nova\Fields\Text; use Laravel\Nova\Http\Requests\NovaRequest; class Invoice extends Resource { public static $model = \App\Models\Invoice::class; public static $title = 'invoice_number'; public static $search = ['invoice_number', 'user.name']; public function fields(NovaRequest $request) { return [ ID::make()->sortable(), // 关联客户User模型 BelongsTo::make('客户', 'user', \App\Nova\User::class) ->rules('required'), // 发票基础信息 Text::make('发票编号', 'invoice_number') ->rules('required', 'unique:invoices'), Date::make('发票日期', 'invoice_date') ->rules('required'), // 动态添加发票项核心配置 \Laravel\Nova\Fields\HasMany::make('发票项', 'invoiceItems', \App\Nova\InvoiceItem::class) ->inlineCreate(function (NovaRequest $request, $parentResource) { // 自定义弹窗内的创建字段 return [ BelongsTo::make('商品', 'product', \App\Nova\Product::class) ->rules('required'), Number::make('数量', 'quantity') ->rules('required', 'integer', 'min:1'), Number::make('单价', 'unit_price') ->rules('required', 'numeric', 'min:0.01') ->currency('CNY'), ]; }) ->inlineEdit() // 支持在详情页直接编辑发票项 ->sortable(), // 动态计算总金额(仅在详情页显示) Number::make('总金额', function () { return $this->invoiceItems->sum(fn($item) => $item->quantity * $item->unit_price); })->onlyOnDetail()->currency('CNY'), ]; } }
4. 配置InvoiceItem资源(可选)
若需要独立管理发票项,在app/Nova/InvoiceItem.php中配置字段:
use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Number; use Laravel\Nova\Http\Requests\NovaRequest; class InvoiceItem extends Resource { public static $model = \App\Models\InvoiceItem::class; public static $title = 'id'; public static $search = ['invoice.invoice_number', 'product.name']; public function fields(NovaRequest $request) { return [ ID::make()->sortable(), BelongsTo::make('发票', 'invoice', \App\Nova\Invoice::class) ->rules('required'), BelongsTo::make('商品', 'product', \App\Nova\Product::class) ->rules('required'), Number::make('数量', 'quantity') ->rules('required', 'integer', 'min:1'), Number::make('单价', 'unit_price') ->rules('required', 'numeric', 'min:0.01') ->currency('CNY'), // 动态计算小计 Number::make('小计', function () { return $this->quantity * $this->unit_price; })->currency('CNY'), ]; } }
5. 关键验证与说明
- 确保模型关联正确:Invoice模型需定义
public function invoiceItems() { return $this->hasMany(InvoiceItem::class); };InvoiceItem模型需定义public function invoice() { return $this->belongsTo(Invoice::class); }和public function product() { return $this->belongsTo(Product::class); }。 inlineCreate实现了在创建Invoice页面直接弹窗添加发票项,无需跳转;inlineEdit支持在详情页快速编辑已有项。- 所有字段添加了验证规则,保障数据合法性。
额外优化建议
- 给发票编号添加自动生成逻辑:在Invoice模型的
creating事件中生成唯一编号,避免手动输入。 - 若需要前端实时计算小计,可自定义Nova字段实现(Nova官方暂不支持原生实时计算)。
- 添加发票状态字段(如「已开票」「已支付」),用
Select字段实现状态切换。
内容的提问来源于stack exchange,提问作者Aseef Ahmed
相关产品推荐
相关产品推荐

