logo

定义指标

Nova 指标可让你快速了解应用程序的关键业务指标。例如,你可以定义一个指标来显示每天添加到应用程序的用户总数,或某个产品的每周销售额。

Nova 提供几种类型的内置指标:值、趋势、分区和进度。下面我们将研究每种类型的指标并演示其用法。

值指标显示单个值,如果需要,还可显示与前一个时间间隔相比的变化。例如,值指标可以显示过去 30 天内创建的用户总数与前 30 天的对比:

Value Metric

可使用 nova:value Artisan 命令生成值类。默认情况下,所有新的值类都将放在 app/Nova/Metrics 目录中:

bash
php artisan nova:value NewUsers

生成值类后,就可以对其进行自定义了。每个值类都包含一个 calculate 方法。该方法应返回一个 Laravel\Nova\Metrics\ValueResult 实例。别担心,Nova 提供了多种快速生成度量结果的助手。

在这个示例中,我们使用了 count 辅助程序,它将针对所选范围的指定 Eloquent 模型自动执行 count 查询,并自动检索「前一个 范围的计数:

php
<?php

namespace App\Nova\Metrics;

use App\Models\User;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Value;

class NewUsers extends Value
{
    /**
     * 计算度量值。
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return mixed
     */
    public function calculate(NovaRequest $request)
    {
        return $this->count($request, User::class);
    }

    /**
     * 获取该指标的可用范围。
     *
     * @return array
     */
    public function ranges()
    {
        return [
            30 => '30 Days',
            60 => '60 Days',
            365 => '365 Days',
            'TODAY' => 'Today',
            'YESTERDAY' => 'Yesterday',
            'MTD' => 'Month To Date',
            'QTD' => 'Quarter To Date',
            'YTD' => 'Year To Date',
        ];
    }

    /**
     * 获取度量值的 URI key。
     *
     * @return string
     */
    public function uriKey()
    {
        return 'new-users';
    }
}

值查询类型

值度量不只包含一个 count 辅助函数。在构建度量时,你还可以使用其他各种聚合函数。现在让我们一一探讨。

平均值

average 方法可用于计算给定列与前一个 时间间隔/范围 相比的平均值:

php
return $this->average($request, Post::class, 'word_count');

总和

可使用 sum 方法计算给定列与上一 时间间隔/范围 的总和:

php
return $this->sum($request, Order::class, 'price');

最大值

max 方法可用于计算给定列与上一 时间间隔/范围 相比的最大值:

php
return $this->max($request, Order::class, 'total');

最小值

min 方法可用于计算给定列与上一 时间间隔/范围 相比的最小值:

php
return $this->min($request, Order::class, 'total');

值范围

每个值度量类都包含一个 ranges 方法。该方法决定了值域范围选择菜单中可用的范围。数组的键决定了应包含在查询中的天数,而值则决定了将放置在范围选择菜单中的 "人类可读" 文本。当然,你也不需要定义任何范围:

php
/**
 * 获取该指标的可用范围。
 *
 * @return array
 */
public function ranges()
{
    return [
        5 => '5 Days',
        10 => '10 Days',
        15 => '15 Days',
        'TODAY' => 'Today',
        'YESTERDAY' => 'Yesterday',
        'MTD' => 'Month To Date',
        'QTD' => 'Quarter To Date',
        'YTD' => 'Year To Date',
        'ALL' => 'All Time'
    ];
}

TODAY / YESTERDAY / MTD / QTD / YTD / ALL 范围关键词

你可以根据自己的需要自定义这些范围;但是,如果你使用的是内置的 "Today", "Yesterday", "Month To Date", "Quarter To Date", "Year To Date", 或 "All Time" 范围,则不应更改它们的键值。

零结果值

默认情况下,Nova 会将 0 的结果处理为不包含数据的结果。这并不总是正确的,所以你可以使用 allowZeroResult 方法来表示 0 是一个有效的结果值:

php
return $this->result(0)->allowZeroResult();

格式化数值

在返回 ValueResult 实例时,你可以调用 prefixsuffix 方法,为值度量结果添加前缀和/或后缀:

php
public function calculate(NovaRequest $request)
{
    return $this->max($request, Order::class, 'total')
                ->prefix('$')
                ->suffix('per unit');
}

你还可以使用 currency 方法指定给定值结果代表货币值。默认情况下,货币符号将是 $,但你您也可以通过将符号作为参数传递给 currency 方法来指定自己的货币符号:

php
return $this->max($request, Order::class, 'total')->currency();

return $this->max($request, Order::class, 'total')->currency('£');

要自定义数值结果的显示格式,可以使用 format 方法。格式必须是 Numbro 支持的格式之一:

php
// Numbro v2.0+ (http://numbrojs.com/format.html)
public function calculate(NovaRequest $request)
{
    return $this->count($request, User::class)
                ->format([
                    'thousandSeparated' => true,
                    'mantissa' => 2,
                ]);
}

// Numbro < v2.0 (http://numbrojs.com/old-format.html)
public function calculate(NovaRequest $request)
{
    return $this->count($request, User::class)
                ->format('0,0');
}

转换数值结果

有时,你可能需要在向用户显示数值结果之前对其进行 "转换"。例如,假设您有一个 "总收入" 指标,它以美分为单位计算产品的总收入。你可能希望以美元或美分为单位向用户显示该值。要在显示之前转换数值,可以使用 transform 助手:

php
public function calculate(NovaRequest $request)
{
    return $this->sum($request, Invoice::class, 'amount')
        ->transform(fn($value) => $value / 100);
}

手动创建值结果

如果你无法使用随附的查询助手来构建您的值度量,你可以使用 resultprevious 方法轻松地手动向度量提供最终值,从而完全控制这些值的计算:

php
return $this->result(100)->previous(50);

趋势

趋势指标通过折线图显示随时间变化的数值。例如,趋势指标可以显示过去 30 天内每天创建的新用户数量:

Trend Metric

可使用 nova:trend Artisan 命令生成趋势指标。默认情况下,所有新指标都将放在 app/Nova/Metrics 目录中:

bash
php artisan nova:trend UsersPerDay

趋势指标类生成后,就可以对其进行自定义了。每个趋势指标类都包含一个 calculate 方法。该方法应返回一个 Laravel\Nova\Metrics\TrendResult 对象。别担心,Nova 提供了多种快速生成结果的助手。

在本例中,我们使用了 countByDays 助手,它将针对选定范围和选定时间间隔单位(本例中为天),自动对指定的 Eloquent 模型执行 count 查询:

php
<?php

namespace App\Nova\Metrics;

use App\Models\User;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Trend;

class UsersPerDay extends Trend
{
    /**
     * 计算度量值。
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return mixed
     */
    public function calculate(NovaRequest $request)
    {
        return $this->countByDays($request, User::class);
    }

    /**
     * 获取度量的可用范围。
     *
     * @return array
     */
    public function ranges()
    {
        return [
            30 => '30 Days',
            60 => '60 Days',
            90 => '90 Days',
        ];
    }

    /**
     * 获取度量的 URI key。
     *
     * @return string
     */
    public function uriKey()
    {
        return 'users-per-day';
    }
}

趋势查询类型

趋势度量不仅带有 countByDays 辅助工具。在构建度量指标时,你还可以使用各种其他聚合函数和时间间隔。

计数

count 方法可用于计算给定列在一段时间内的计数:

php
return $this->countByMonths($request, User::class);
return $this->countByWeeks($request, User::class);
return $this->countByDays($request, User::class);
return $this->countByHours($request, User::class);
return $this->countByMinutes($request, User::class);

平均

average 方法可用于计算给定列在一段时间内的平均值:

php
return $this->averageByMonths($request, Post::class, 'word_count');
return $this->averageByWeeks($request, Post::class, 'word_count');
return $this->averageByDays($request, Post::class, 'word_count');
return $this->averageByHours($request, Post::class, 'word_count');
return $this->averageByMinutes($request, Post::class, 'word_count');

总和

sum 方法可用于计算给定列在一段时间内的总和:

php
return $this->sumByMonths($request, Order::class, 'price');
return $this->sumByWeeks($request, Order::class, 'price');
return $this->sumByDays($request, Order::class, 'price');
return $this->sumByHours($request, Order::class, 'price');
return $this->sumByMinutes($request, Order::class, 'price');

最大值

max 方法可用于计算给定列在一段时间内的最大值:

php
return $this->maxByMonths($request, Order::class, 'total');
return $this->maxByWeeks($request, Order::class, 'total');
return $this->maxByDays($request, Order::class, 'total');
return $this->maxByHours($request, Order::class, 'total');
return $this->maxByMinutes($request, Order::class, 'total');

最小值

min 方法可用于计算给定列在一段时间内的最小值:

php
return $this->minByMonths($request, Order::class, 'total');
return $this->minByWeeks($request, Order::class, 'total');
return $this->minByDays($request, Order::class, 'total');
return $this->minByHours($request, Order::class, 'total');
return $this->minByMinutes($request, Order::class, 'total');

趋势范围

每个趋势度量类都包含一个 ranges 方法。该方法决定趋势度量的范围选择菜单中可用的范围。数组的键决定了查询中应包含的时间间隔单位(月、周、日等)的数量,而值则决定了范围选择菜单中的「人类可读」文本。当然,你也不需要定义任何范围:

php
/**
 * 获取该指标的可用范围。
 *
 * @return array
 */
public function ranges()
{
    return [
        5 => '5 Days',
        10 => '10 Days',
        15 => '15 Days',
    ];
}

显示当前值

有时,你可能希望强调最新趋势度量时间间隔的值。例如,在本截图中,最近一天创建了 6 个用户:

Latest Value

为此,你可以使用 showLatestValue 方法:

php
return $this->countByDays($request, User::class)
            ->showLatestValue();

要自定义数值结果的显示格式,可以使用 format 方法。格式必须是 Numbro 支持的格式之一:

php
// Numbro v2.0+ (http://numbrojs.com/format.html)
public function calculate(NovaRequest $request)
{
    return $this->count($request, User::class)
                ->format([
                    'thousandSeparated' => true,
                    'mantissa' => 2,
                ]);
}

// Numbro < v2.0 (http://numbrojs.com/old-format.html)
public function calculate(NovaRequest $request)
{
    return $this->count($request, User::class)
                ->format('0,0');
}

显示趋势总和

默认情况下,Nova 只将趋势指标的最后一个值显示为强调的「当前」值。不过,有时您可能希望显示趋势的总计数。你可以在返回趋势度量值时调用 showSumValue 方法来实现这一点:

php
return $this->countByDays($request, User::class)
            ->showSumValue();

趋势值格式化

有时,你可能希望在被强调的「当前」趋势值上添加前缀或后缀。为此,你可以使用 prefixsuffix 方法:

php
return $this->sumByDays($request, Order::class, 'price')->prefix('$');

如果你的趋势度量显示的是货币值,你可以使用 dollarseuros 方便的方法在趋势值前快速添加美元或欧元符号:

php
return $this->sumByDays($request, Order::class, 'price')->dollars();

手动创建趋势结果

如果无法使用随附的查询助手来构建趋势度量,则可以手动构建 Laravel\Nova\Metrics\TrendResult 对象,并从度量的 calculate 方法中返回。这种计算趋势数据的方法可以让你在构建图表数据时拥有完全的灵活性:

php
return (new TrendResult)->trend([
    'July 1' => 100,
    'July 2' => 150,
    'July 3' => 200,
]);

分区指标

分区指标显示的是饼状图的数值。例如,分区指标可以显示应用程序提供的每个计费计划的用户总数:

Partition Metric

可使用 nova:partition Artisan 命令生成分区指标。默认情况下,所有新的度量指标都将放在 app/Nova/Metrics 目录中:

bash
php artisan nova:partition UsersPerPlan

生成分区指标类后,就可以对其进行自定义了。每个分区指标类都包含一个 calculate 方法。该方法应返回一个 Laravel\Nova\Metrics\PartitionResult 对象。别担心,Nova 提供了多种快速生成结果的助手。

在这个示例中,我们使用了 count 辅助程序,它会自动对指定的 Eloquent 模型执行 count 查询,并检索属于指定的「group by」列中每个不同值的模型数量:

php
<?php

namespace App\Nova\Metrics;

use App\Models\User;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Partition;

class UsersPerPlan extends Partition
{
    /**
     * 计算度量值。
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return mixed
     */
    public function calculate(NovaRequest $request)
    {
        return $this->count($request, User::class, 'stripe_plan');
    }

    /**
     * 获取度量值的 URI key。
     *
     * @return string
     */
    public function uriKey()
    {
        return 'users-by-plan';
    }
}

分区查询类型

分区度量不只包含一个 count 辅助函数。在建立度量时,你还可以使用其他各种聚合函数。

平均

average 方法可用于计算不同组中给定列的平均值。例如,以下对 average 方法的调用将显示一个饼图,其中包含公司各部门的平均订单价格:

php
return $this->average($request, Order::class, 'price', 'department');

总和

sum 方法可用于计算不同组中给定列的总和。例如,以下对 sum 方法的调用将显示一个饼图,其中包含公司各部门所有订单价格的总和:

php
return $this->sum($request, Order::class, 'price', 'department');

最大值

max 方法可用于计算不同组中给定列的最大值。例如,以下对 max 方法的调用将显示一个饼图,其中包含公司各部门的最大订单价格:

php
return $this->max($request, Order::class, 'price', 'department');

最小值

min 方法可用于计算不同组中给定列的最小值。例如,以下对 min 方法的调用将显示一个饼图,其中包含公司各部门的最低订单价格:

php
return $this->min($request, Order::class, 'price', 'department');

自定义分区标签

通常情况下,将分区度量划分为组的列值是简单的键,而不是「人类可读」的值。或者,如果你显示的分区度量是由布尔列分组的,Nova 会将分组标签显示为「0」和「1」。因此,Nova 允许你提供一个闭包,将标签格式化为更易于阅读的格式:

php
/**
 * 计算度量值。
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return mixed
 */
public function calculate(NovaRequest $request)
{
    return $this->count($request, User::class, 'stripe_plan')
            ->label(fn ($value) => match ($value) {
                null => 'None',
                default => ucfirst($value)
            });
}

自定义隔板颜色

默认情况下,Nova 会选择分区度量中使用的颜色。有时,你可能希望更改这些颜色,以便更好地匹配它们所代表的数据类型。为此,你可以在从度量返回分区结果时调用 colors 方法:

php
/**
 * 计算度量值。
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return mixed
 */
public function calculate(NovaRequest $request)
{
    // 这一指标包含类型 `audio`, `video`, and `photo`...
    return $this->count($request, Post::class, 'type')->colors([
        'audio' => '#6ab04c',
        'video' => 'rgb(72,52,212)',
        // 由于没有指定,「photo 将使用 Nova 的默认颜色。...
    ]);
}

手动创建分区结果

如果无法使用随附的查询助手来构建分区度量,则可使用 result 方法手动向度量提供最终值,从而提供最大的灵活性:

php
return $this->result([
    'Group 1' => 100,
    'Group 2' => 200,
    'Group 3' => 300,
]);

进度指标

进度指标在柱形图中显示当前进度与目标值的对比情况。例如,进度指标可以显示特定月份的注册用户数与目标值的比较:

Progress Metric

进度指标可使用 nova:progress Artisan 命令生成。默认情况下,所有新指标都将放在 app/Nova/Metrics 目录中:

bash
php artisan nova:progress NewUsers

进度指标类生成后,就可以对其进行自定义了。每个进度指标类都包含一个 calculate 方法。该方法应返回一个 Laravel\Nova\Metrics\ProgressResult 对象。别担心,Nova 提供了多种快速生成结果的助手。

在本示例中,我们使用 count 辅助程序来确定是否已达到本月的新用户注册目标。count 辅助程序将自动针对指定的 Eloquent 模型执行 count 查询:

php
<?php

namespace App\Nova\Metrics;

use App\Models\User;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Progress;

class NewUsers extends Progress
{
    /**
     * 计算度量值。
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return mixed
     */
    public function calculate(NovaRequest $request)
    {
        return $this->count($request, User::class, function ($query) {
            return $query->where('created_at', '>=', now()->startOfMonth());
        }, target: 200);
    }

    /**
     * 获取度量值的 URI key。
     *
     * @return string
     */
    public function uriKey()
    {
        return 'new-users';
    }
}

总和

进度度量不仅带有 count 辅助工具。在创建度量时,你还可以使用 sum 聚合方法。例如,下面对 sum 方法的调用将显示一个进度指标,其中包含已完成交易金额与目标销售额的总和:

php
return $this->sum($request, Transaction::class, function ($query) {
    return $query->where('completed', '=', 1);
}, 'amount', target: 2000);

不想要的进度

有时,你可能要跟踪实现「目标」的进展情况,而你却不希望看到这种情况,例如某个月内取消订单的客户数量。在这种情况下,当你接近「目标」时,你通常希望进度指标的颜色不再是绿色。

当使用 avoid 方法指定您希望避免的指标时,Nova 将使用绿色表示在实现「目标」方面缺乏进展,而使用黄色表示「目标」即将完成:

php
return $this->count($request, User::class, function ($query) {
    return $query->where('cancelled_at', '>=', now()->startOfMonth());
}, target: 200)->avoid();

设置进度值的格式

有时,你可能希望为当前进度值添加前缀或后缀。为此,你可以使用 prefixsuffix 方法:

php
return $this->sum($request, Transaction::class, function ($query) {
    return $query->where('completed', '=', 1);
}, 'amount', target: 2000)->prefix('$');

如果进度指标显示的是货币值,则可以使用 dollarseuros 方便的方法在进度值前快速添加美元或欧元符号:

php
return $this->sum($request, Transaction::class, function ($query) {
    return $query->where('completed', '=', 1);
}, 'amount', target: 2000)->dollars();

手动创建进度结果

如果无法使用随附的查询助手来构建进度指标,可以使用 result 方法手动向指标提供最终值:

php
return $this->result(80, 100);

表格指标

表格指标允许你显示自定义链接列表、操作列表以及可选图标。

可使用 nova:table Artisan 命令生成表格指标。默认情况下,所有新的指标都将放在 app/Nova/Metrics 目录中:

php
php artisan nova:table NewReleases

生成表格指标类后,就可以对其进行自定义了。每个表格指标类都包含一个 calculate 方法。该方法应返回一个 Laravel\Nova\Metrics\MetricTableRow 对象数组。每个度量行都允许你指定标题和副标题,它们将堆叠显示在该行上:

php
<?php

namespace App\Nova\Metrics;

use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Table;

class NewReleases extends Table
{
    /**
     * 计算度量值。
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return mixed
     */
    public function calculate(NovaRequest $request)
    {
        return [
            MetricTableRow::make()
                ->title('v1.0')
                ->subtitle('Initial release of Laravel Nova'),

            MetricTableRow::make()
                ->title('v2.0')
                ->subtitle('The second major series of Laravel Nova'),
        ];
    }
}

为表格行添加动作

虽然表格指标非常适合用于显示进度、文档链接或模型的最新条目,但通过附加动作,它们会变得更加强大。

Table Actions

你可以使用 actions 方法返回 Laravel\Nova\Menu\MenuItem 实例的数组,这些实例将显示在下拉菜单中:

php
<?php

namespace App\Nova\Metrics;

use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Table;

class NewReleases extends Table
{
    /**
     * 计算度量值。
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return mixed
     */
    public function calculate(NovaRequest $request)
    {
        return [
            MetricTableRow::make()
                ->title('v1.0')
                ->subtitle('Initial release of Laravel Nova')
                ->actions(function () {
                    return [
                        MenuItem::externalLink('View release notes', '/releases/1.0'),
                        MenuItem::externalLink('Share on Twitter', 'https://twitter.com/intent/tweet?text=Check%20out%20the%20new%20release'),
                    ];
                }),

            MetricTableRow::make()
                ->title('v2.0 (pre-release)')
                ->subtitle('The second major series of Laravel Nova')
                ->actions(function () {
                    return [
                        MenuItem::externalLink('View release notes', '/releases/2.0'),
                        MenuItem::externalLink('Share on Twitter', 'https://twitter.com/intent/tweet?text=Check%20out%20the%20new%20release'),
                    ];
                }),
        ];
    }
}

自定义菜单项

你可以阅读 菜单项自定义文档,了解有关菜单自定义的更多信息。

在表格行上显示图标

表格指标还支持在每一行的标题和副标题左侧显示图标。你可以使用这些信息按类型直观地划分不同的表格行,或使用它们来显示内部流程的进度。

Table Icons

要在表格指标行上显示图标,请使用 icon 方法并输入你希望使用的图标的键值:

php
<?php

namespace App\Nova\Metrics;

use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Table;

class NextSteps extends Table
{
    /**
     * 计算度量值。
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return mixed
     */
    public function calculate(NovaRequest $request)
    {
        return [
            MetricTableRow::make()
                ->icon('check-circle')
                ->iconClass('text-green-500')
                ->title('Get your welcome kit from HR')
                ->subtitle('Includes a Macbook Pro and swag!'),

            MetricTableRow::make()
                ->icon('check-circle')
                ->iconClass('text-green-500')
                ->title('Bootstrap your development environment')
                ->subtitle('Install the repository and get your credentials.'),

            MetricTableRow::make()
                ->icon('check-circle')
                ->iconClass('text-gray-400 dark:text-gray-700')
                ->title('Make your first production deployment')
                ->subtitle('Push your first code change to our servers.'),
        ];
    }
}

你可以使用 iconClass 方法为图标添加所需的类,从而通过 CSS 自定义图标的颜色:

php
MetricTableRow::make()
    ->icon('check-circle')
    ->iconClass('text-gray-400 dark:text-gray-700')
    ->title('Make your first production deployment')
    ->subtitle('Push your first code change to our servers.'),

Heroicons 图标

Nova 使用设计者 Steve Schoger 提供的免费图标集 Heroicons UI。请随意使用这些图标,以匹配 Nova 内置图标的外观和感觉。

自定义表格度量空文本

如果你表格度量是动态生成行,有时可能会出现无结果显示的情况。默认情况下,Nova 会向用户显示 "未找到结果..."。

但有时你可能希望自定义此文本,以便为用户提供更多上下文提示信息。例如,如果你创建了一个名为 "最近用户" 的表指标,但没有任何用户要显示。你可以使用 emptyText 方法自定义显示的信息:

php
use App\Nova\Metrics\RecentUsers;
use Laravel\Nova\Http\Requests\NovaRequest;

/**
 * 获取资源可用的卡片。
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function cards(NovaRequest $request)
{
    return [
        RecentUsers::make()->emptyText('There are no recent users.');
    ];
}

缓存

有时,指标值的计算既慢又昂贵。因此,所有 Nova 指标都包含一个 cacheFor 方法,允许你指定指标结果的缓存时间:

php
/**
 * 确定指标结果的缓存时间。
 *
 * @return \DateTimeInterface|\DateInterval|float|int|null
 */
public function cacheFor()
{
    return now()->addMinutes(5);
}

自定义指标类名称

默认情况下,Nova 将使用指标类名称作为指标的可显示名称。你可以通过重载指标类中的 name 方法,自定义显示在指标卡上的指标名称:

php
/**
 * 获取指标类的可显示名称
 *
 * @return string
 */
public function name()
{
    return 'Users Created';
}