CaiWuXiTong/modules/EcommerceFinance/View/OrderProfitPageData.php
renshen 31de7272e3 feat: 订单利润支持支付发货时间筛选 (#983)
订单利润支持支付时间、发货时间、订单时间筛选;先分页订单键再汇总当前页,补充日期索引与性能优化。
2026-11-07 16:21:24 +08:00

171 lines
5.4 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
{
private const DATE_FIELDS = [
'pay_time' => '支付时间',
'send_time' => '发货时间',
'order_time' => '订单时间',
];
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{date_field:string,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);
$dateField = trim((string) ($input['date_field'] ?? 'pay_time'));
if (! isset(self::DATE_FIELDS[$dateField])) {
$dateField = 'pay_time';
}
if (! $datesWereSubmitted && ! $reset && ! $hasOtherFilters) {
$from = now()->subDays(6)->toDateString();
$to = now()->toDateString();
}
return [
'date_field' => $dateField,
'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;
}
}