$end) { [$start, $end] = [$end, $start]; } return [$start, $end]; } /** @return array */ public function page(Request $request): array { $filters = $this->filters($request); $page = max((int) $request->query('page', 1), 1); $perPage = self::normalizePerPage($request->query('per_page')); $paginationQuery = array_filter( [...$filters, 'per_page' => $perPage], static fn (mixed $value): bool => $value !== '' && $value !== null, ); try { $options = $this->repository->filterOptions($filters); if ($filters['payment_state'] !== '' && ! in_array($filters['payment_state'], $options['payment_states'], true)) { $filters['payment_state'] = ''; unset($paginationQuery['payment_state']); } $result = $this->repository->paginate($filters, $page, $perPage); return [ 'processRows' => new LengthAwarePaginator( $result['data'], $result['total'], $perPage, $page, ['path' => $request->url(), 'query' => $paginationQuery], ), 'filters' => $filters, 'summary' => $result['summary'], 'documentTypes' => $options['document_types'], 'statuses' => $options['statuses'], 'paymentStates' => $options['payment_states'], 'mirrorStatus' => $result['status'], 'mirrorSyncedAt' => $result['last_synced_at'], 'mirrorStale' => $result['sync_stale'] ?? false, 'mirrorStaleAfterMinutes' => $result['sync_stale_after_minutes'] ?? 15, 'scope' => $result['scope'], 'error' => null, ]; } catch (Throwable $exception) { report($exception); return [ 'processRows' => new LengthAwarePaginator([], 0, $perPage, $page, [ 'path' => $request->url(), 'query' => $paginationQuery, ]), 'filters' => $filters, 'summary' => [ 'rows' => 0, 'approvals' => 0, 'amount_total' => 0.0, 'bank_amount_total' => 0.0, ], 'documentTypes' => [], 'statuses' => [], 'paymentStates' => [], 'mirrorStatus' => 'unavailable', 'mirrorSyncedAt' => null, 'mirrorStale' => false, 'mirrorStaleAfterMinutes' => 15, 'scope' => $this->repository->scope(), 'error' => 'OA流程镜像尚未完成导入,请稍后重试。', ]; } } /** @return array */ private function filters(Request $request): array { $status = DingProcessDetailMirrorRepository::normalizeStatusFilter( $request->query('status', ''), ); [$paidStart, $paidEnd] = self::normalizePaidDateRange( $request->query('paid_start'), $request->query('paid_end'), $request->query('paid_date'), ); $paymentState = DingProcessDetailMirrorRepository::normalizePaymentStateFilter( $request->query('payment_state'), ); return [ 'paid_start' => $paidStart, 'paid_end' => $paidEnd, 'document_type' => mb_substr(trim((string) $request->query('document_type', '')), 0, 100), 'status' => mb_substr($status, 0, 20), 'payment_state' => $paymentState, 'business_id' => mb_substr(trim((string) $request->query('business_id', '')), 0, 32), 'originator_name' => mb_substr(trim((string) $request->query('originator_name', '')), 0, 100), 'keyword' => mb_substr(trim((string) $request->query('keyword', '')), 0, 100), ]; } private static function normalizeFilterDate(mixed $value): string { $date = trim((string) $value); if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $date, $parts) !== 1 || ! checkdate((int) $parts[2], (int) $parts[3], (int) $parts[1])) { return ''; } return $date; } }