revosystems/sidecar

Laravel 报告工具


README

安装

composer require revosystems/sidecar

您需要在主模板中包含 tailwind 2.xapline 3.x

将 blades 路径添加到 tailwindcss 配置文件

purge: [
    ...
    './vendor/revosystems/sidecar/**/*.blade.php',
  ],

并定义品牌颜色如下

theme: {
    extend: {
      colors: {
        'brand': '#F2653A',
      }
    },
  },

您还应该在主模板的头部包含 chart.js 和 choices.js,使用此行

{!! \Revo\Sidecar\Sidecar::dependencies() !!}

配置

发布配置以适应您的项目

php artisan vendor:publish

config/sidecar.php 中,您可以找到以下参数,可以根据您的项目进行修改

assets/css/sidecar.css 中,您可以找到默认样式

您应该将这些文件添加到您的资产编译中

全局变量

您可以通过实现 serving callback 来自定义一些运行时变量

class AppServiceProvider extends ServiceProvider	
    public function boot() {
        Sidecar::$usesMultitenant = true;	// When true, all the caches and jobs will use the `auth()->user()->id` as prefix
	    Sidecar::serving(function(){	
	            \Revo\Sidecar\ExportFields\Date::$timezone = auth()->user()->timezone;							// The timezone to display the dates
	            \Revo\Sidecar\ExportFields\Date::$openingTime = auth()->user()->getBusiness()->openingTime;		// To define a day change time instead of 00:00
	            \Revo\Sidecar\ExportFields\Currency::setFormatter('es_ES', auth()->user()->currency ?? 'EUR');	// For the currency field
        });
    }

报告

要创建报告,您应该创建一个名为 WathereverYouWantReport 的新文件(注意它需要以 Report 结尾)在配置文件 reportsPath 中定义的文件夹中。此报告类需要扩展主要的 Revo\Sidecar\Report

并定义主要模型类以及实现 fields 方法

<?php

namespace App\Reports;

use Revo\Sidecar\Report;
use App\Post;

class OrdersReport extends Report {

	protected $model  = Post::class;

	public function getFields() : array{
     	return [ ];	
    }
}

现在我们只需要定义我们想要在报告中显示的字段

我们还可以添加默认查询过滤器,通过覆盖 query() 方法

public function query() : Builder {
    return parent::query()->withTrashed();
}

我们还可以在右上角添加 MainActions 作为按钮。

public function mainActions(): array
{
    return [
        MainAction::make(?string $title = null, ?string $icon = null, ?string $url = '')
    ];
}

更多功能

字段

您可以使用简单的数组定义导出字段,大多数都共享相同的特性

创建

ExportField::make($field, $title, $dependsOnField)

默认选项
文本

· 在过滤时将执行 like 并允许您输入自定义搜索文本

数字

· 它将使行居右对齐 · 在分组时,默认执行求和操作(您可以使用 onGroupingBy() 函数进行更改) · 在过滤时允许您选择运算符和数量 · 提供函数 trimZeros(),该函数将删除十进制值的尾随零

十进制

· 从数字扩展而来

货币

· 从数字扩展而来

百分比

· 从数字扩展而来,并在 HTML 导出中添加 % 符号

日期

· 此字段允许不同的分组选项(小时、天、星期、周、月、季度) · 启用可过滤时,默认使用过去 7 天 · filterOnClick 选项执行深度分组过滤,因此如果按月分组,并且单击十一月,则将仅过滤十一月,按周分组 · 日期字段还带有 timeFilterable(),该功能还显示时间范围过滤器

计算

· 此字段允许您对字段执行操作,例如 Computed::make('guests/total') · 您可以定义分组操作 Computed::make('guests/total')->onGroupingBy('sum(guests)/sum(total)')

Id

· Id 字段显示行的 id · 在分组时执行计数 · 当分组时,通常只使用 id Id::make()->onlyWhenGrouping()

BelongsTo

· 当你的模型中存在属于关系时,你可以使用这个字段来自动创建过滤器/组。默认情况下,它将使用关系中的 name 字段,使用 relationShipDisplayField($field) 函数使用另一个字段。在排序/分组时会执行所需的连接。
· 你可以通过提供 ID 列表来限定 belongs by 过滤器的选项 filterOptionsIdsScope()
· 如果你需要始终执行连接,可以调用 defaultJoin()

通常,你会过滤整个查询以避免访问问题。

BelongsToThrough

· 当你的模型中存在 belongs to through 关系时,你可以使用这个字段来自动创建过滤器/组,它将执行...默认情况下,它将使用关系中的 name 字段,使用 relationShipDisplayField($field) 函数使用另一个字段。你需要使用 through() 函数定义中转关系 BelongsToThrough::make('user')->trough('comment')。在排序/分组时会执行所需的连接。

HasMany

· 这个字段将显示所有与 hasMany 模型相关的信息,将名称压缩为 , 。默认情况下,它将使用关系中的 name 字段,你可以使用 relationShipDisplayField($field) 来更改它。这个字段不可过滤也不可分组。

HasOne

· 它提供了 defaultJoin() 选项以在每个查询中执行连接。它不可过滤也不可分组。

Enum

· 它适用于枚举字段(常量)如 statustype。存在 options() 函数,你可以定义一个数组 [["value" => "displayName"]],该数组将用于显示和过滤。

Icon

· 一个简单的字段,将使用 field 值作为图标名称显示 fontawesome 图标。

创建你的 ExportField

你可以通过扩展任何之前字段或主要的 Sidecar\ExportFields\ExportField 来创建自己的导出字段。

<?php

namespace App\Reports\Sidecar;

use Revo\Sidecar\ExportFields\Link;

class Preview extends Link
{
    protected ?string $linkClasses = "showPopup";

    public static function make($field, $title = null, $dependsOnField = null)
    {
        $field = parent::make($field, $title, $dependsOnField);
        $field->route = $title;
        return $field;
    }

    public function getTitle(): string
    {
        return "";
    }

    public function getLinkTitle($row) : string {
        return '<i class="fa fa-eye fa-fw"></i>';
    }

    public function toHtml($row): string
    {
        $link = route($this->route, $this->getValue($row));
        return "<a href='{$link}' class='{$this->linkClasses}' style='color:gray;'>{$this->getLinkTitle($row)}</a>";
    }
}

ExportField 有一个 toHtml($row) 函数,这是在浏览器中显示值时使用的函数,在导出到 CSV 时将使用 getValue($row),因此你可以自定义两者。

通常,会覆盖 getFilterKey() 为类似 non-filterable 的内容,以避免与常用字段冲突。在这种情况下,此 Preview 文件将与 Id 字段冲突,因为它是链接中使用的字段。

小部件

报告可以定义一组小部件来总结显示的内容(非分页),因此当它不分组时将显示它们。目前只有两种可能的小部件。

<?php

namespace App\Reports\V2;

use App\Models\Orders\Order;

use Revo\Sidecar\Widgets\Count;
use Revo\Sidecar\Widgets\Sum;

class OrdersReport extends Report
{
    protected $model  = Order::class;

    public function getFields() : array{
        return [
            ...
        ];	
    }

    public function getWidgets() : array
    {
        return [
            Count::make('id', __('admin.count')),
            Sum::make('guests', trans_choice('admin.guest', 2)),
        ];
    }

}

仪表板

Sidecar 还附带了一些漂亮的仪表板面板,可以嵌入到任何页面中。

你只需要创建一个,通过扩展 Revo\Sidecar\Panel 并定义所需的 dimensionmetric。你需要传递要应用于此报告的过滤器。

<?php

namespace App\Reports\V2\Sidecar\Widgets;

use App\Models\Orders\Order;
use App\Reports\V2\OrdersReport;
use Illuminate\Database\Eloquent\Builder;
use Revo\Sidecar\ExportFields\Currency;
use Revo\Sidecar\ExportFields\Date;
use Revo\Sidecar\ExportFields\ExportField;
use Revo\Sidecar\Filters\Filters;
use Revo\Sidecar\Panels\Panel;

class Sales extends Panel
{
    protected $model            = Order::class;
    protected ?string $tooltip  = "salesByDayDesc";

    public function query() : Builder{
        return parent::query()->whereNull('canceled')->whereNull('merged')->whereNotNull('opened');
    }

    public function __construct()
    {
        $filters = (new Filters())->groupingBy(['opened' => 'day'])
                                  ->forPeriod('opened', 'last30days')
                                  ->sortBy('opened', 'asc');
        parent::__construct("salesByDay", $filters);
    }

    public function metricField(): ExportField
    {
        return Currency::make('total');
    }

    public function dimensionField(): ExportField
    {
        return Date::make('opened')->filterable();
    }

    public function getFullReportLink(): ?string
    {
        return url('reports/v2/orders?' . $this->filters->getQueryString() );
    }
}

你可以实现 getFullReportLink() 来链接到完整报告。注意 $filters->getQueryString() 返回用于 url 的查询字符串。

最后,你可以使用类似以下方式在 blade 中渲染它们

<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
    @foreach($panels as $panel)
        {!! $panel->render() !!}
    @endforeach
</div>

这些仪表板面板将在第二天之前进行缓存,并使用 Ajax 加载。

面板类型

通过枚举 PanelType 定义了不同的 Panels 类型,例如 barlisttrend(默认)和 pie

class TopPaymentMethods extends Panel
{
    ...

    public PanelType $type = PanelType::pie;

    ...
}
``