新增订单利润页面、共享镜像查询、筛选聚合、明细展示、列设置与导出。 验证:20 项测试通过,249 个断言;真实页面代表订单 26092142570188 验收通过。
160 lines
5.0 KiB
PHP
160 lines
5.0 KiB
PHP
<?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;
|
||
}
|
||
}
|