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

Laravel使用whereBetween按项目最新报告筛选数据错误如何解决?

问题根源

  1. 你自定义的latest关联仅在预加载(with)数据时会自动取最新一条报告,whereHas查询时不会做单条限制,只要项目下存在任意符合variance区间的报告就会被返回,所以结果不符合预期。
  2. 原代码whereBetween的参数存在语法错误,数组缺少右方括号,会直接导致查询报错。

一、后端Laravel侧修改

1. 修正关联定义(Laravel 8及以上版本推荐)

用Laravel官方提供的ofMany方法定义最新报告的一对一关联,whereHas查询时会自动匹配唯一的最新报告,准确性更高:

// Project模型中修改latest方法
public function latest()
{
    return $this->hasOne(Report::class)->ofMany([
        'year' => 'DESC',
        'month' => 'DESC',
    ]);
}

2. 修正控制器查询逻辑

补全查询构造器初始化,修正语法错误,补充参数格式处理:

public function index(Request $request)
{
    $project = $this->_getData($request);
    return response()->json($project);
}
 
private function _getData(Request $request)
{
    // 补全查询构造器初始化 原代码漏了这行
    $project = \App\Models\Project::query();

    if ($request->query('customer', false)) {
        $project->where('customer_id', $request->query('customer'));
    }

    if ($request->filled('range')) {
        // 拆分区间并去除空格
        $range = array_map('trim', explode('~', $request->query('range')));
        // 格式校验 避免非法参数
        if (count($range) == 2 && is_numeric($range[0]) && is_numeric($range[1])) {
            $project->whereHas('latest',function ($query) use ($range){
                // 修正原语法错误 补全数组右括号
                $query->whereBetween('variance', [$range[0], $range[1]]);
            });
        }
    }

    return $project->orderBy('project_name')->paginate(5);
}

低版本Laravel兼容方案

如果是Laravel 8以下版本,直接用子查询实现过滤,不需要修改关联定义:

// 替换区间过滤逻辑即可
if ($request->filled('range')) {
    $range = array_map('trim', explode('~', $request->query('range')));
    if (count($range) == 2 && is_numeric($range[0]) && is_numeric($range[1])) {
        $project->whereRaw(
            "(SELECT variance FROM reports WHERE project_id = projects.id ORDER BY year DESC, month DESC LIMIT 1) BETWEEN ? AND ?",
            $range
        );
    }
}

二、前端Vue侧适配

1. 接口参数格式化

统一将区间值拼接为最小值~最大值的字符串传递给后端,示例:

// 假设页面有varianceMin、varianceMax两个绑定变量存储区间值
async fetchProjectList(page = 1) {
  const params = {
    page,
    customer: this.selectedCustomerId || '',
    range: `${this.varianceMin}~${this.varianceMax}`
  }
  const res = await axios.get('/api/projects', { params })
  this.projectList = res.data.data
  // 存储分页信息
  this.pagination = {
    total: res.data.total,
    currentPage: res.data.current_page,
    perPage: res.data.per_page
  }
}

2. 分页逻辑适配

翻页时需要携带当前所有过滤参数(客户ID、区间值),避免翻页时过滤条件丢失:

// 分页组件切换页码时触发
handlePageChange(page) {
  this.fetchProjectList(page)
}

3. 输入兼容处理

如果是手动输入区间的场景,放开负号、小数点的输入限制,避免前端拦截合法的负数、小数参数。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:24:03