CaiWuXiTong/modules/EcommerceFinance/View/OrderProfitPageData.php
renshen 3bd2587c04 feat: 新增订单利润页面与明细查询 (#786)
新增订单利润页面、共享镜像查询、筛选聚合、明细展示、列设置与导出。

验证:20 项测试通过,249 个断言;真实页面代表订单 26092142570188 验收通过。
2026-10-30 15:24:09 +08:00

160 lines
5.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Modules\EcommerceFinance\View;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
use Modules\EcommerceFinance\Repositories\OrderProfitRepository;
use Throwable;
class OrderProfitPageData
{
public function __construct(private readonly OrderProfitRepository $repository)
{
}
public function page(): array
{
return ['view' => 'business.pages.order-data.order-profit'] + $this->data();
}
public function data(?array $input = null, ?int $page = null, ?int $limit = null): array
{
$filters = $this->filters($input);
$page = max($page ?? (int) request('page', 1), 1);
$limit = min(max($limit ?? (int) setting('default.list_limit', 25), 1), 100);
$rows = $this->paginator([], $filters, $page, $limit);
$error = null;
$status = $this->repository->status();
$hasFilters = $this->hasFilters($filters);
if ($hasFilters && ($status['ready'] ?? false)) {
try {
$result = $this->repository->paginate($filters, $page, $limit);
$rows = $this->paginator(
(array) ($result['rows'] ?? []),
$filters,
$page,
$limit,
(bool) ($result['has_more'] ?? false),
);
} catch (Throwable $exception) {
report($exception);
$error = '订单利润数据暂时无法读取,请稍后重试。';
}
} elseif ($hasFilters && ! ($status['ready'] ?? false)) {
$error = '订单利润共享镜像尚未完成首次同步。';
}
return [
'orderProfitRows' => $rows,
'orderProfitFilters' => $filters,
'orderProfitShopOptions' => $this->repository->shopNames(),
'orderProfitStatus' => $status,
'orderProfitError' => $error,
'orderProfitHasFilters' => $hasFilters,
];
}
/** @return array{from:string,to:string,order_no:string,shop_name:string,shop_names:array<int,string>,sku_id:string} */
private function filters(?array $input): array
{
$input ??= request()->query();
$shops = [];
$rawShops = $input['shop_name'] ?? $input['shop_names'] ?? [];
foreach ((array) $rawShops as $shop) {
$shop = trim((string) $shop);
if ($shop !== '') {
$shops[$shop] = true;
}
if (count($shops) >= 50) {
break;
}
}
$orderNo = $this->batchText($input['order_no'] ?? null);
$sku = $this->batchText($input['sku_id'] ?? null);
$hasOtherFilters = $orderNo !== '' || $sku !== '' || $shops !== [];
$datesWereSubmitted = array_key_exists('from', $input) || array_key_exists('to', $input);
$reset = ! empty($input['reset']);
$from = $this->date($input['from'] ?? null);
$to = $this->date($input['to'] ?? null);
if (! $datesWereSubmitted && ! $reset && ! $hasOtherFilters) {
$from = now()->subDays(6)->toDateString();
$to = now()->toDateString();
}
return [
'from' => $from,
'to' => $to,
'order_no' => $orderNo,
'shop_name' => implode("\n", array_keys($shops)),
'shop_names' => array_keys($shops),
'sku_id' => $sku,
];
}
private function date(mixed $value): string
{
$value = trim((string) $value);
if ($value === '') {
return '';
}
$timestamp = strtotime($value);
return $timestamp === false ? '' : date('Y-m-d', $timestamp);
}
private function batchText(mixed $value): string
{
$values = is_array($value) ? $value : preg_split('/[\r\n,,;;]+/u', (string) $value);
$items = [];
foreach ((array) $values as $item) {
$item = trim((string) $item);
if ($item !== '') {
$items[$item] = true;
}
if (count($items) >= 100) {
break;
}
}
return implode("\n", array_keys($items));
}
private function hasFilters(array $filters): bool
{
return trim((string) $filters['order_no']) !== ''
|| trim((string) $filters['shop_name']) !== ''
|| trim((string) $filters['sku_id']) !== ''
|| $filters['from'] !== ''
|| $filters['to'] !== '';
}
private function paginator(
array $rows,
array $filters,
int $page,
int $limit,
?bool $hasMore = null,
): Paginator {
$paginator = new Paginator(
Collection::make($rows)->map(static fn (array $row): object => (object) $row),
$limit,
$page,
[
'path' => request()->url(),
'query' => request()->except('page'),
],
);
if ($hasMore !== null) {
$paginator->hasMorePagesWhen($hasMore);
}
return $paginator;
}
}