From 9cca643a7ed696785fdd66bb86cebebd5d29c8ff Mon Sep 17 00:00:00 2001 From: yueyang <2495544247@qq.com> Date: Thu, 24 Sep 2026 15:47:46 +0800 Subject: [PATCH] =?UTF-8?q?perf(small-payment-work-orders):=20=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E9=87=91=E9=A2=9D=E5=90=88=E8=AE=A1=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E9=94=AE=E9=9B=86=E5=88=86=E5=9D=97=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 只取金额所需字段,按 w.Id 键集分块批量读取,避免逐行游标造成的每行一次网络往返 - 抽出 PAYMENT_AMOUNT_FIELDS 常量,与行内金额解析共用,避免口径漂移 - 抽出 centsFromMoney/formatCents,去掉重复的金额累加逻辑 --- .../SmallPaymentWorkOrderMirrorRepository.php | 73 +++++++++++++++---- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/modules/EcommerceFinance/Repositories/SmallPaymentWorkOrderMirrorRepository.php b/modules/EcommerceFinance/Repositories/SmallPaymentWorkOrderMirrorRepository.php index a949e337..fcc80bb6 100644 --- a/modules/EcommerceFinance/Repositories/SmallPaymentWorkOrderMirrorRepository.php +++ b/modules/EcommerceFinance/Repositories/SmallPaymentWorkOrderMirrorRepository.php @@ -40,6 +40,9 @@ class SmallPaymentWorkOrderMirrorRepository private const COMPLETED_WORK_ORDER_STATUSES = ['CONFIRMED', '已完成', '已确认']; + /** 打款金额在 businessFieldList 中的候选字段名(按优先级) */ + private const PAYMENT_AMOUNT_FIELDS = ['打款金额', '付款金额', '小额打款金额', 'amountField']; + private readonly ConnectionInterface $connection; public function __construct( @@ -177,18 +180,48 @@ class SmallPaymentWorkOrderMirrorRepository } /** + * 统计当前筛选条件下全部记录的打款金额合计。 + * + * 只取金额所需字段,按 Id 做键集分块批量读取:不使用逐行游标(本地/远端库时每次取行都是一次网络往返), + * 也不复用导出用的分页排序查询(会为大结果集重复执行连接与排序)。 + * * @param array{from:string,to:string,work_order_no:string,shop_name:string,transaction_no:string,online_order_no:string,status:string,payment_reason:string} $filters */ - public function filteredPaymentAmount(array $filters): string + public function filteredPaymentAmount(array $filters, int $chunkSize = 1000): string { $this->ensureReady(); - $amounts = []; - foreach ($this->exportRows($filters, 100) as $row) { - $amounts[] = $row['payment_amount'] ?? null; - } + $query = $this->baseQuery(); + $this->applyFilters($query, $filters); - return $this->sumMoney($amounts); + $chunkSize = min(max($chunkSize, 100), 5000); + $cents = 0; + $lastId = null; + + do { + $chunk = (clone $query) + ->select(['w.Id AS source_id', 'w.businessFieldList']) + ->when($lastId !== null, static fn (Builder $q): Builder => $q->where('w.Id', '>', $lastId)) + ->orderBy('w.Id') + ->limit($chunkSize) + ->get(); + + foreach ($chunk as $row) { + $cents += $this->centsFromMoney($this->paymentAmountOf($row->businessFieldList ?? null)); + } + + $lastId = $chunk->isEmpty() ? null : $chunk->last()->source_id; + } while ($chunk->count() === $chunkSize); + + return $this->formatCents($cents); + } + + private function paymentAmountOf(mixed $businessFieldList): ?string + { + return $this->money($this->field( + $this->businessFields($businessFieldList), + self::PAYMENT_AMOUNT_FIELDS, + )); } /** @@ -390,9 +423,7 @@ class SmallPaymentWorkOrderMirrorRepository $row['alipay_batch_no'] = $this->field($fields, [ '支付宝批次号', '支付宝打款批次号', '打款批次号', '批次号', 'alipayBatchNo', 'batchNo', ]); - $row['payment_amount'] = $this->money($this->field($fields, [ - '打款金额', '付款金额', '小额打款金额', 'amountField', - ])); + $row['payment_amount'] = $this->money($this->field($fields, self::PAYMENT_AMOUNT_FIELDS)); $row['online_order_no'] = $this->firstFilled( $this->field($fields, ['线上订单号', '线上单号', '订单号', 'orderField']), $row['mapped_online_order_no'] ?? null, @@ -535,14 +566,26 @@ class SmallPaymentWorkOrderMirrorRepository { $cents = 0; foreach ($amounts as $amount) { - if ($amount === null || ! preg_match('/^(-?)(\d+)\.(\d{2})$/', (string) $amount, $matches)) { - continue; - } - - $value = ((int) $matches[2] * 100) + (int) $matches[3]; - $cents += $matches[1] === '-' ? -$value : $value; + $cents += $this->centsFromMoney($amount); } + return $this->formatCents($cents); + } + + /** 将 '123.45' / '-123.45' 形式的金额字符串转成分(无效值计 0)。 */ + private function centsFromMoney(mixed $amount): int + { + if ($amount === null || ! preg_match('/^(-?)(\d+)\.(\d{2})$/', (string) $amount, $matches)) { + return 0; + } + + $value = ((int) $matches[2] * 100) + (int) $matches[3]; + + return $matches[1] === '-' ? -$value : $value; + } + + private function formatCents(int $cents): string + { $sign = $cents < 0 ? '-' : ''; $absolute = abs($cents);