You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel实现工作评分总分存储及按供应商ID计算平均分方案

Laravel 工作评分持久化与供应商平均分计算落地方案

1. 数据库结构调整

首先新增total_score字段存储单条工作的总分,同时回填历史数据:

  • 生成迁移文件
    执行Artisan命令创建迁移:
php artisan make:migration add_total_score_to_pekerjaans_table --table=pekerjaans
  • 编辑迁移文件
    打开database/migrations/目录下刚生成的迁移文件,写入字段新增与历史数据回填逻辑:
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Pekerjaan;

return new class extends Migration
{
    public function up()
    {
        Schema::table('pekerjaans', function (Blueprint $table) {
            // 总分字段放在nilai_4之后,默认值0
            $table->integer('total_score')->default(0)->after('nilai_4');
        });

        // 回填历史数据的总分
        Pekerjaan::chunk(100, function ($list) {
            foreach ($list as $item) {
                $item->total_score = $item->nilai_1 + $item->nilai_2 + $item->nilai_3 + $item->nilai_4;
                $item->saveQuietly();
            }
        });
    }

    public function down()
    {
        Schema::table('pekerjaans', function (Blueprint $table) {
            $table->dropColumn('total_score');
        });
    }
};
  • 执行迁移生效
php artisan migrate

2. 模型层逻辑配置

2.1 Pekerjaan(工作)模型配置

  • 将total_score加入批量赋值白名单
  • 注册模型保存事件,新增/更新时自动计算总分,无需每次手动编写重复计算逻辑
    打开app/Models/Pekerjaan.php,添加如下代码:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Pekerjaan extends Model
{
    // 加入total_score到fillable数组
    protected $fillable = [
        'penyedia_id',
        'nilai_1',
        'nilai_2',
        'nilai_3',
        'nilai_4',
        'total_score',
        // 其余原有字段保留即可
    ];

    // 模型启动时注册自动计算事件
    protected static function booted()
    {
        // 新增、更新记录前自动计算总分写入
        static::saving(function ($pekerjaan) {
            $pekerjaan->total_score = collect([
                $pekerjaan->nilai_1,
                $pekerjaan->nilai_2,
                $pekerjaan->nilai_3,
                $pekerjaan->nilai_4
            ])->sum();
        });
    }

    // 原有与供应商的关联保留
    public function penyedia()
    {
        return $this->belongsTo(Penyedia::class);
    }
}

2.2 Penyedia(供应商)模型配置

添加平均分访问器,直接基于已持久化的total_score计算,避免视图层写零散的计算逻辑:
打开app/Models/Penyedia.php,添加如下代码:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Penyedia extends Model
{
    // 如果需要JSON/API输出自动携带平均分,可加入appends数组
    protected $appends = ['average_score'];

    // 原有一对多关联保留
    public function pekerjaans()
    {
        return $this->hasMany(Pekerjaan::class);
    }

    // 平均分访问器,默认保留2位小数
    public function getAverageScoreAttribute()
    {
        // 无工作记录时返回0,避免null导致页面报错
        return round($this->pekerjaans()->avg('total_score') ?? 0, 2);
    }
}

3. 控制器层优化

原有评分更新逻辑无需大幅改动,模型事件会自动处理总分持久化;查询供应商列表时增加预加载避免N+1性能问题:

// 评分更新方法(原有逻辑微调即可)
public function updateScore(Request $request, Pekerjaan $pekerjaan)
{
    $validated = $request->validate([
        'nilai_1' => 'required|integer|min:0|max:100',
        'nilai_2' => 'required|integer|min:0|max:100',
        'nilai_3' => 'required|integer|min:0|max:100',
        'nilai_4' => 'required|integer|min:0|max:100',
    ]);

    $pekerjaan->update($validated);
    // 无需手动计算total_score,模型saving事件自动完成写入

    return back()->with('success', '评分更新成功');
}

// 供应商列表查询方法
public function penyediaList()
{
    // 预加载工作记录,避免循环查询平均分触发N+1问题
    $penyediaList = Penyedia::with('pekerjaans')->get();
    return view('penyedia.index', compact('penyediaList'));
}

4. Blade视图调用

删除原有临时计算总分、平均分的零散逻辑,直接调用模型属性即可:

  • 单条工作总分展示:
<!-- 替换原有临时计算的{{ $item->nilai_1 + $item->nilai_2 + $item->nilai_3 + $item->nilai_4 }} -->
<tr>
    <td>{{ $item->nama_pekerjaan }}</td>
    <td>{{ $item->nilai_1 }}</td>
    <td>{{ $item->nilai_2 }}</td>
    <td>{{ $item->nilai_3 }}</td>
    <td>{{ $item->nilai_4 }}</td>
    <td>*{{ $item->total_score }}*</td>
</tr>
  • 供应商平均分展示:
@foreach($penyediaList as $penyedia)
<tr>
    <td>{{ $penyedia->nama_penyedia }}</td>
    <td>{{ $penyedia->pekerjaans->count() }} 条工作记录</td>
    <td>*{{ $penyedia->average_score }}*</td>
</tr>
@endforeach

注意事项

  • 若使用批量更新语法(如Pekerjaan::where(...)->update(...))不会触发模型事件,需在批量更新后手动重算对应记录的总分
  • 若评分字段为浮点数,把迁移里的integer类型改成float/decimal即可,上层计算逻辑无需调整

内容的提问来源于stack exchange,提问作者YuPi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:57:20