如何用Laravel Vite优化资源打包并改进献血系统代码?
问题1:如何使用Laravel Vite对HTML、CSS和JS进行资源打包优化?
Laravel Vite是Laravel官方推荐的前端构建工具,以下是具体的优化步骤:
1. 基础配置确认
确保你的Laravel版本在9.x及以上(默认集成Vite),旧版本可通过以下命令升级并安装Vite:
composer require laravel/vite-plugin npm install
2. 规范资源目录结构
将前端资源按类型组织在resources/js和resources/css目录下:
- 入口文件:
resources/js/app.js(统一导入JS模块和CSS) - 样式文件:
resources/css/app.css(或使用Sass/Tailwind等预处理器)
3. CSS打包优化
- 提取公共样式:将复用样式抽离为单独文件(如
resources/css/components/button.css),在app.css中导入 - 预处理器支持:安装Sass依赖后直接使用,Vite自动编译:
将样式文件改为npm install sass.scss后缀,在app.js中导入:import '../css/app.scss'; - 生产环境压缩:执行
npm run build时,Vite会自动压缩CSS代码
4. JS打包优化
- 模块化开发:将JS代码拆分为多个模块(如
resources/js/utils/validation.js),通过ES6 import导入,Vite自动执行Tree Shaking移除未使用代码 - 代码分割:使用动态导入实现按需加载,比如路由组件:
const Dashboard = () => import('./pages/Dashboard.vue'); - 生产环境混淆:
npm run build会自动混淆压缩JS代码,减小体积
5. 资源引用与缓存优化
- 在Blade模板中使用
@vite指令加载资源,自动处理版本哈希(避免浏览器缓存旧资源):@vite(['resources/js/app.js', 'resources/css/app.css']) - 自定义Vite配置(
vite.config.js),修改资源输出目录或添加CDN前缀:import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; export default defineConfig({ plugins: [ laravel({ input: ['resources/js/app.js', 'resources/css/app.css'], buildDirectory: 'build', // 自定义构建目录 }), ], });
6. 额外优化
- 图片处理:使用
vite-plugin-imagetools压缩图片、支持WebP格式:
配置后在代码中导入图片:npm install vite-plugin-imagetoolsimport logo from '../images/logo.png?w=200&format=webp'; - 字体优化:将本地字体放在
resources/fonts目录,在CSS中引用,Vite自动处理打包和缓存
问题2:献血管理系统代码改进方案
以下是针对这套代码的具体改进点,覆盖数据库、模型、控制器、视图等核心层面:
一、数据库层优化
1. 增加字段约束与索引
修改迁移文件,为blood_type和status添加枚举约束,同时添加索引提升查询性能:
public function up(): void { Schema::create('blood_donations', function (Blueprint $table) { $table->id(); $table->string('donor_name', 255); // 血型枚举约束 $table->enum('blood_type', ['A+','A-','B+','B-','AB+','AB-','O+','O-']); $table->integer('bags')->default(1)->unsigned(); // 袋数禁止为负 // 状态枚举约束,默认可用 $table->enum('status', ['available', 'used', 'expired'])->default('available'); $table->date('donation_date'); $table->date('expiry_date')->nullable(); $table->timestamps(); $table->softDeletes(); // 新增软删除字段 // 添加索引加速查询 $table->index('blood_type'); $table->index('status'); $table->index('donation_date'); }); }
2. 自动计算过期日期
献血血液有效期通常为6个月,可在迁移后通过模型观察者自动设置,避免手动输入。
二、模型层优化
1. 使用枚举常量替代硬编码
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class BloodDonation extends Model { use SoftDeletes; // 血型枚举常量 const BLOOD_TYPES = ['A+','A-','B+','B-','AB+','AB-','O+','O-']; // 状态枚举常量 const STATUS_AVAILABLE = 'available'; const STATUS_USED = 'used'; const STATUS_EXPIRED = 'expired'; protected $fillable = [ 'donor_name', 'blood_type', 'bags', 'status', 'donation_date', 'expiry_date' ]; protected $dates = ['deleted_at']; // 自动设置过期日期 protected static function booted() { static::creating(function ($donation) { if (!$donation->expiry_date) { $donation->expiry_date = $donation->donation_date->addMonths(6); } }); } // 作用域:查询可用血液 public function scopeAvailable($query) { return $query->where('status', self::STATUS_AVAILABLE); } // 访问器:格式化状态为中文 public function getStatusLabelAttribute() { return match($this->status) { self::STATUS_AVAILABLE => '可用', self::STATUS_USED => '已使用', self::STATUS_EXPIRED => '已过期', default => '未知' }; } }
三、控制器层优化
1. 用表单请求类分离验证逻辑
创建StoreBloodDonationRequest和UpdateBloodDonationRequest类,替代控制器内的验证代码:
php artisan make:request StoreBloodDonationRequest
请求类示例:
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use App\Models\BloodDonation; class StoreBloodDonationRequest extends FormRequest { public function authorize() { return auth()->check(); // 仅登录用户可提交 } public function rules() { return [ 'donor_name' => 'required|string|max:255', 'blood_type' => 'required|in:'.implode(',', BloodDonation::BLOOD_TYPES), 'bags' => 'required|integer|min:1|max:10', // 限制袋数范围 'status' => 'required|in:'.implode(',', [BloodDonation::STATUS_AVAILABLE, BloodDonation::STATUS_USED, BloodDonation::STATUS_EXPIRED]), 'donation_date' => 'required|date|before_or_equal:today', ]; } // 自定义中文错误消息 public function messages() { return [ 'blood_type.in' => '血型必须选择指定的有效类型', 'status.in' => '状态只能是可用、已使用或已过期', ]; } }
控制器中使用:
public function store(StoreBloodDonationRequest $request) { BloodDonation::create($request->validated()); return redirect()->route('blood-donations.index')->with('success', '记录已添加!'); }
2. 优化报表查询性能
将集合过滤改为数据库原生查询,减少内存占用:
private function getData() { $query = BloodDonation::query(); // 统计总数据 $total = $query->count(); $available = $query->where('status', BloodDonation::STATUS_AVAILABLE)->sum('bags'); $used = $query->where('status', BloodDonation::STATUS_USED)->sum('bags'); $expired = $query->where('status', BloodDonation::STATUS_EXPIRED)->sum('bags'); // 按血型分组统计 $summary = $query->selectRaw('blood_type, SUM(bags) as total') ->selectRaw('SUM(CASE WHEN status = ? THEN bags ELSE 0 END) as available', [BloodDonation::STATUS_AVAILABLE]) ->selectRaw('SUM(CASE WHEN status = ? THEN bags ELSE 0 END) as used', [BloodDonation::STATUS_USED]) ->selectRaw('SUM(CASE WHEN status = ? THEN bags ELSE 0 END) as expired', [BloodDonation::STATUS_EXPIRED]) ->groupBy('blood_type') ->get() ->keyBy('blood_type'); // 补全所有血型,避免缺失 $fullSummary = []; foreach (BloodDonation::BLOOD_TYPES as $type) { $fullSummary[] = $summary->get($type, [ 'type' => $type, 'total' => 0, 'available' => 0, 'used' => 0, 'expired' => 0, ]); } return [ 'total' => $total, 'available' => $available, 'used' => $used, 'expired' => $expired, 'summary' => $fullSummary, 'donations' => $query->latest()->get(), ]; }
四、路由优化
1. 增加权限控制
使用Laravel Gate或权限包(如spatie/laravel-permission)添加权限验证:
Route::middleware(['auth', 'can:manage-blood-donations'])->group(function () { Route::resource('blood-donations', BloodDonationController::class); Route::get('/blood-reports', [BloodReportController::class, 'index'])->name('blood-reports.index'); Route::get('/blood-reports/pdf', [BloodReportController::class, 'exportPdf'])->name('blood-reports.pdf'); Route::get('/blood-reports/excel', [BloodReportController::class, 'exportExcel'])->name('blood-reports.excel'); });
2. 简化资源路由
仅保留需要的资源控制器方法:
Route::resource('blood-donations', BloodDonationController::class)->only(['index', 'create', 'store', 'edit', 'update', 'destroy']);
五、视图层优化
1. 完善表单与错误提示
在创建/编辑表单中添加所有字段,并显示验证错误:
{{-- 创建页表单 --}} <form method="POST" action="{{ route('blood-donations.store') }}"> @csrf <div> <label for="donor_name">献血者姓名</label> <input type="text" name="donor_name" id="donor_name" value="{{ old('donor_name') }}" required> @error('donor_name') <span class="text-red-500">{{ $message }}</span> @enderror </div> <div> <label for="blood_type">血型</label> <select name="blood_type" id="blood_type" required> @foreach(App\Models\BloodDonation::BLOOD_TYPES as $type) <option value="{{ $type }}" {{ old('blood_type') == $type ? 'selected' : '' }}>{{ $type }}</option> @endforeach </select> @error('blood_type') <span class="text-red-500">{{ $message }}</span> @enderror </div> <!-- 袋数、状态、献血日期字段省略 --> <button type="submit">保存</button> </form>
2. 分页与操作按钮优化
{{-- 列表页 --}} @forelse($donations as $d) <div> <p>{{ $d->donor_name }} | {{ $d->blood_type }} | {{ $d->status_label }}</p> <a href="{{ route('blood-donations.edit', $d) }}">编辑</a> <form action="{{ route('blood-donations.destroy',$d) }}" method="POST" class="inline"> @csrf @method('DELETE') <button type="submit" onclick="return confirm('确定要删除吗?')">删除</button> </form> </div> @empty <p>暂无记录。</p> @endforelse {{-- 分页链接 --}} {{ $donations->links() }}
六、报表导出优化
1. 支持日期范围筛选
避免导出全部数据,添加日期筛选:
public function exportExcel(Request $request) { $query = BloodDonation::query(); if ($request->start_date) { $query->where('donation_date', '>=', $request->start_date); } if ($request->end_date) { $query->where('donation_date', '<=', $request->end_date); } return Excel::download(new BloodReportExport($query), 'blood-report.xlsx'); }
修改导出类接收查询参数:
class BloodReportExport implements FromCollection, WithHeadings { private $query; public function __construct($query) { $this->query = $query; } public function collection() { return $this->query->select( 'donor_name','blood_type','bags','status','donation_date' )->get(); } public function headings(): array { return ['献血者姓名','血型','袋数','状态','献血日期']; } }
2. 异步处理大文件导出
使用Laravel队列避免请求超时:
public function exportPdf(Request $request) { dispatch(new ExportBloodReportPdfJob($request->all())); return redirect()->route('blood-reports.index')->with('success', '报表正在生成,稍后将通知您!'); }
七、安全与性能优化
1. 缓存统计数据
缓存报表统计数据,减少数据库查询:
private function getData() { return Cache::remember('blood-report-data', 3600, function () { // 原查询逻辑 }); }
2. 防止批量赋值漏洞
严格控制$fillable字段,避免意外赋值;或使用$guarded = []明确允许所有字段赋值(需确保字段安全)。
内容的提问来源于stack exchange,提问作者Chingchongg
相关产品推荐
相关产品推荐

