From cad8369fdbebe29d3f1864e08bfa1cbf4ad95da3 Mon Sep 17 00:00:00 2001 From: yueyang <2495544247@qq.com> Date: Tue, 20 Oct 2026 11:28:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=9A=E7=BB=A9=E6=98=8E=E7=BB=86=EF=BC=9A?= =?UTF-8?q?=E6=96=B0=E5=A2=9E1688=E7=BA=A2=E5=8C=85=E8=A1=A5=E8=B4=B4?= =?UTF-8?q?=E5=A4=87=E6=B3=A8=E5=B9=B6=E4=BC=98=E5=8C=96=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Business/Pages.php | 364 ++++++++++++++---- .../pages/partials/directory-table.blade.php | 11 +- .../pages/partials/multi-select.blade.php | 10 +- 3 files changed, 304 insertions(+), 81 deletions(-) diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index e07e2363..829e8ac4 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -289,14 +289,21 @@ class Pages extends Controller ]; } + private static function receiptReasonNotBasisMarkedSql(): string + { + return "COALESCE(remark, '') NOT IN ('订单实付按卖家实收核对', '订单实付按应付/已付核对')"; + } + /** - * 「差额异常备注」原因(不落库):说明差额为什么产生,一行最多一个,按顺序取第一条命中。 - * 未匹配行 → 订单实付未匹配(细分原因见「未匹配原因」列);已匹配但基准金额=0 → 订单实付取数为0; - * 基准金额没有减掉优惠/冲减时,差额正好等于对应项。差额按有效值判定(未匹配按基准金额=0)。 + * 「差额异常备注」基础原因(不落库),按页面优先级排列。 * - * @return array 备注文字 => SQL 条件(已按顺序排除前面命中的行) + * 这里保留可重叠的原始条件;需要“一行只取第一个原因”时走 + * receiptDifferenceRemarkIndexSql(),由单次 CASE 按顺序命中,避免把 + * 前序大段条件重复拼进后续每一条,拖慢筛选联动。 + * + * @return array 备注文字 => 原始 SQL 条件 */ - private static function receiptDifferenceRemarkConditions(): array + private static function receiptDifferenceRemarkBaseRules(): array { $basis = self::differenceBasis(); $column = $basis['column']; @@ -367,7 +374,7 @@ class Pages extends Controller $rules['差额=订单实付包含商家承担优惠'] = $jdSofiaGuard . ' AND NOT (' . $jdSofiaGuobu . ')'; // C 方案:这三条是"通用等式档"——口径(卖家实收 / 应付已付)能对上账单的行让位给口径兜底 // (归零 + 口径标识),只有口径也对不上时才显示这三档,避免把口径差标成一堆"未减优惠/冲减"。 - $notBasisMarked = "COALESCE(remark, '') NOT IN ('订单实付按卖家实收核对', '订单实付按应付/已付核对')"; + $notBasisMarked = self::receiptReasonNotBasisMarkedSql(); $rules[$label . '未减冲减'] = "match_status = '已匹配' AND ABS(COALESCE($column, 0) - (COALESCE(income_amount, 0) + COALESCE(discount_amount, 0))) < 0.005 AND " . $notBasisMarked; $rules[$label . '未减优惠'] = "match_status = '已匹配' AND ABS(COALESCE($column, 0) - (COALESCE(income_amount, 0) + COALESCE(offset_amount, 0))) < 0.005 AND " . $notBasisMarked; $rules[$label . '未减优惠和冲减'] = "match_status = '已匹配' AND ABS(COALESCE($column, 0) - COALESCE(income_amount, 0)) < 0.005 AND " . $notBasisMarked; @@ -405,27 +412,53 @@ class Pages extends Controller . ' OR ' . $refundFullHit($refundEvidence['refund_sum']) . ') ELSE 0 END = 1) OR ' . $taoRefundHit; + // 1688 先采后付订单的订单实付包含平台红包补贴,但支付宝实际到账是扣除补贴后的现金; + // 仅对已匹配、负差额、无优惠/冲减/退款且当前没有口径标识的行标注,不改差额金额。 + $rules['订单实付含平台红包补贴'] = "platform = '淘系支付宝'" + . " AND (store_name LIKE '新佰广%' OR store_name LIKE '阿里巴巴%' OR store_name LIKE '1688%')" + . ' AND match_status = \'已匹配\'' + . ' AND ' . $effective . ' < -0.005' + . ' AND ABS(COALESCE(discount_amount, 0)) < 0.005' + . ' AND ABS(COALESCE(offset_amount, 0)) < 0.005' + . ' AND ABS(COALESCE(refund_amount, 0)) < 0.005' + . ' AND COALESCE(paid_amount, 0) > COALESCE(income_amount, 0) + 0.005' + . ' AND ' . $notBasisMarked; + // 京喜分位尾差:具体原因都没命中时,1–3 分钱按四舍五入尾差标注。 $rules['差额=分位四舍五入尾差'] = "platform = '京喜账单' AND ABS(" . $effective . ') <= 0.0301 AND ' . $notBasisMarked; - $conditions = []; - $seen = []; - foreach ($rules as $label => $condition) { - $condition = 'ABS(' . $effective . ') > 0.005 AND (' . $condition . ')'; - $conditions[$label] = $seen === [] ? $condition : $condition . ' AND NOT (' . implode(' OR ', $seen) . ')'; - $seen[] = '(' . $condition . ')'; + return $rules; + } + + /** @return list 差额异常备注的下拉顺序(含兜底档) */ + private static function receiptDifferenceRemarkLabels(): array + { + return array_merge(array_keys(self::receiptDifferenceRemarkBaseRules()), ['差额待核实']); + } + + /** + * 差额异常备注的优先级序号(1 开始;0=无备注)。 + * + * 单次 CASE 命中后即停止,筛选统计与备注筛选共用同一口径。相比把 + * 18 条条件逐条带上前序 NOT 再分别 SUM,避免重复计算退款等关联子查询。 + */ + private static function receiptDifferenceRemarkIndexSql(): string + { + $effective = 'COALESCE(difference, COALESCE(income_amount, 0) + COALESCE(discount_amount, 0) + COALESCE(offset_amount, 0))'; + $sql = 'CASE WHEN ABS(' . $effective . ') <= 0.005 THEN 0'; + $index = 1; + foreach (self::receiptDifferenceRemarkBaseRules() as $condition) { + $sql .= ' WHEN (' . $condition . ') THEN ' . $index; + $index++; } - // 兜底档:有差额但没命中任何原因 →「差额待核实」(与页面渲染的兜底备注保持一致)。 - $conditions['差额待核实'] = 'ABS(' . $effective . ') > 0.005 AND NOT (' . implode(' OR ', $seen) . ') AND ' . $notBasisMarked; - - return $conditions; + return $sql . ' WHEN ' . self::receiptReasonNotBasisMarkedSql() . ' THEN ' . $index . ' ELSE 0 END'; } /** * 该单的聚水潭应付(主单优先 pay_amount)是否大于账单收入(= 含国补/补贴类差额的口径)。 * - * 与 receiptDifferenceRemarkConditions() 里的聚水潭应付款子查询同口径;按单号缓存应付金额, + * 与 receiptDifferenceRemarkBaseRules() 里的聚水潭应付款子查询同口径;按单号缓存应付金额, * 页面渲染与导出逐行调用时不会对同一单重复查询。 */ private static function receiptJdSubsidyPayExceedsIncome(string $orderNo, float $income): bool @@ -496,6 +529,13 @@ class Pages extends Controller return abs((float) ($row->paid_amount ?? 0) - (float) ($row->product_amount ?? 0)) < 0.02; } + private static function is1688StoreName(string $storeName): bool + { + return str_starts_with($storeName, '新佰广') + || str_starts_with($storeName, '阿里巴巴') + || str_starts_with($storeName, '1688'); + } + /** 单行的「差额异常备注」(与筛选条件同一套口径,页面与导出共用)。 */ /** * 页面口径的「有效差额」SQL:口径兜底行(备注为空、但能对上实收/应付)按 0 计。 @@ -503,17 +543,10 @@ class Pages extends Controller */ private static function receiptEffectiveDifferenceSql(): string { - // 注意:要把「差额待核实」这条兜底规则排除掉,否则它本身就是"都没命中", - // 会让这里永远不成立(口径兜底行就归不了零)。 - $rules = self::receiptDifferenceRemarkConditions(); - unset($rules['差额待核实']); - $ruleUnion = '(' . implode(' OR ', array_map( - static fn (string $condition): string => '(' . $condition . ')', - $rules - )) . ')'; - + // 备注序号 > 0 表示命中了明确原因;只有口径兜底且没有明确原因时才归零。 + $indexSql = self::receiptDifferenceRemarkIndexSql(); return "CASE WHEN remark IN (" . self::receiptBasisFallbackSqlList() . ')' - . " AND NOT COALESCE({$ruleUnion}, 0) THEN 0" + . " AND COALESCE({$indexSql}, 0) = 0 THEN 0" . ' ELSE ' . self::receiptDefaultDifferenceSql() . ' END'; } @@ -529,14 +562,7 @@ class Pages extends Controller */ private static function receiptFallbackDifferenceAdjustmentSql(): string { - $rules = self::receiptDifferenceRemarkConditions(); - unset($rules['差额待核实']); - $ruleUnion = '(' . implode(' OR ', array_map( - static fn (string $condition): string => '(' . $condition . ')', - $rules - )) . ')'; - - return 'CASE WHEN NOT COALESCE(' . $ruleUnion . ', 0) THEN -(' + return 'CASE WHEN COALESCE(' . self::receiptDifferenceRemarkIndexSql() . ', 0) = 0 THEN -(' . self::receiptDefaultDifferenceSql() . ') ELSE 0 END'; } @@ -688,6 +714,18 @@ class Pages extends Controller return null; } + // 1688 先采后付红包补贴:订单实付包含平台补贴,支付宝到账只含现金部分。 + // 先只作为已知原因标注,不改变差额金额或税务收入。 + if (($row->platform ?? '') === '淘系支付宝' + && $difference < -0.005 + && self::is1688StoreName((string) ($row->store_name ?? '')) + && abs($discount) < 0.005 + && abs($offset) < 0.005 + && abs((float) ($row->refund_amount ?? 0)) < 0.005 + && (float) ($row->paid_amount ?? 0) > $income + 0.005) { + return '订单实付含平台红包补贴'; + } + // 京喜分位尾差:具体原因都没命中时,1–3 分钱按四舍五入尾差标注。 if (($row->platform ?? '') === '京喜账单' && abs($difference) <= 0.0301) { return '差额=分位四舍五入尾差'; @@ -1346,7 +1384,7 @@ class Pages extends Controller ))); $stats['status_options'] = self::RECEIPT_STATUS_OPTIONS; // 差额异常备注下拉:只保留「差额为什么产生」的原因备注(按差额公式判定) - $stats['remark_options'] = array_values(array_keys(self::receiptDifferenceRemarkConditions())); + $stats['remark_options'] = self::receiptDifferenceRemarkLabels(); // 未匹配原因下拉:未匹配行在库里的原因标注 $stats['unmatched_reason_options'] = self::unmatchedReasonOptions(); @@ -1419,20 +1457,21 @@ class Pages extends Controller return; } - $differenceConditions = self::receiptDifferenceRemarkConditions(); - $differenceLabels = array_values(array_intersect($remarkFilter, array_keys($differenceConditions))); - if ($differenceLabels === []) { + $labels = self::receiptDifferenceRemarkLabels(); + $indexes = []; + foreach ($remarkFilter as $label) { + $index = array_search($label, $labels, true); + if ($index !== false) { + $indexes[] = (int) $index + 1; + } + } + if ($indexes === []) { return; } - $query->where(function ($group) use ($differenceLabels, $differenceConditions): void { - foreach ($differenceLabels as $index => $label) { - $method = $index === 0 ? 'where' : 'orWhere'; - $group->{$method}(function ($sub) use ($label, $differenceConditions): void { - $sub->whereRaw($differenceConditions[$label]); - }); - } - }); + $query->whereRaw( + self::receiptDifferenceRemarkIndexSql() . ' IN (' . implode(', ', array_unique($indexes)) . ')' + ); } /** @@ -1626,18 +1665,192 @@ class Pages extends Controller return response()->json(cache()->remember($cacheKey, now()->addSeconds(600), function () use ($month, $filters, $orderNo) { return [ 'month' => substr($month, 0, 7), - 'facets' => [ - 'platform' => $this->receiptOrderMatchFacet($month, 'platform', $filters, $orderNo, self::RECEIPT_PLATFORM_OPTIONS), - 'store_name' => $this->receiptOrderMatchFacet($month, 'store_name', $filters, $orderNo), - 'match_status' => $this->receiptOrderMatchFacet($month, 'match_status', $filters, $orderNo, self::RECEIPT_STATUS_OPTIONS), - 'remark' => $this->receiptOrderMatchFacet($month, 'remark', $filters, $orderNo, array_keys(self::receiptDifferenceRemarkConditions())), - 'unmatched_reason' => $this->receiptOrderMatchFacet($month, 'unmatched_reason', $filters, $orderNo, self::unmatchedReasonOptions()), - 'difference_state' => $this->receiptDifferenceStateFacet($month, $filters, $orderNo), - ], + 'facets' => $this->receiptOrderMatchFacets($month, $filters, $orderNo), ]; })); } + /** + * 一次请求生成全部筛选联动计数。 + * + * 多个筛选项如果共用同一组“其它条件”,只查一次再一起聚合。页面当前先按 + * 差额备注筛选时,原先 6 次重复全表条件判断会合并成 2 次查询。 + * + * @param array> $filters + * @return array,counts:array}> + */ + private function receiptOrderMatchFacets(string $month, array $filters, string $orderNo): array + { + $facetOrder = [ + 'platform' => self::RECEIPT_PLATFORM_OPTIONS, + 'store_name' => [], + 'match_status' => self::RECEIPT_STATUS_OPTIONS, + 'remark' => self::receiptDifferenceRemarkLabels(), + 'unmatched_reason' => self::unmatchedReasonOptions(), + 'difference_state' => ['有差额', '无差额'], + ]; + + // “统计某个筛选本身”时排除该筛选;条件完全相同的筛选项合并成一个查询。 + $groups = []; + foreach (array_keys($facetOrder) as $column) { + $signature = $filters; + unset($signature[$column]); + $signature = array_filter( + $signature, + static fn ($values): bool => $values !== [] && $values !== '' + ); + ksort($signature); + $key = md5(serialize([$orderNo, $signature])); + $groups[$key]['filters'] = $signature; + $groups[$key]['columns'][] = $column; + } + + $facets = []; + foreach ($groups as $group) { + if ($group['filters'] === []) { + foreach ($group['columns'] as $column) { + $facets[$column] = $column === 'difference_state' + ? $this->receiptDifferenceStateFacet($month, $filters, $orderNo) + : $this->receiptOrderMatchFacet($month, $column, $filters, $orderNo, $facetOrder[$column]); + } + continue; + } + + $counts = $this->receiptOrderMatchFilteredFacetCounts( + $month, + $group['filters'], + $orderNo, + $group['columns'] + ); + foreach ($group['columns'] as $column) { + $columnCounts = $counts[$column] ?? []; + $ordered = array_values(array_intersect($facetOrder[$column], array_keys($columnCounts))); + $rest = array_values(array_diff(array_keys($columnCounts), $ordered)); + sort($rest, SORT_NATURAL | SORT_FLAG_CASE); + $facets[$column] = [ + 'values' => array_merge($ordered, $rest), + 'counts' => $columnCounts, + ]; + } + } + + return array_replace(array_fill_keys(array_keys($facetOrder), ['values' => [], 'counts' => []]), $facets); + } + + /** + * 共用同一组筛选条件时,一次分组查询算出多个筛选项的计数。 + * + * @param array> $filters + * @param list $columns + * @return array> + */ + private function receiptOrderMatchFilteredFacetCounts(string $month, array $filters, string $orderNo, array $columns): array + { + $labels = self::receiptDifferenceRemarkLabels(); + $basisMarks = ['订单实付按卖家实收核对', '订单实付按应付/已付核对']; + $remarkIndexes = []; + foreach ((array) ($filters['remark'] ?? []) as $label) { + $index = array_search($label, $labels, true); + if ($index !== false) { + $remarkIndexes[] = (int) $index + 1; + } + } + $differenceValues = array_map('strval', (array) ($filters['difference_state'] ?? [])); + $wantDifference = in_array('有差额', $differenceValues, true); + $wantNoDifference = in_array('无差额', $differenceValues, true); + + $connection = (string) config('upstream_mirrors.connection', 'business_mirror'); + $inner = DB::connection($connection) + ->table('store_receipt_order_match_rows') + ->where('report_month', $month) + ->select(['platform', 'store_name', 'match_status', 'remark']) + ->selectRaw(self::receiptDefaultDifferenceSql() . ' AS base_difference') + ->selectRaw(self::receiptDifferenceRemarkIndexSql() . ' AS reason_index'); + + foreach ($filters as $key => $values) { + if ($key === 'remark' || $key === 'difference_state' || $values === []) { + continue; + } + if ($key === 'unmatched_reason') { + $this->applyReceiptUnmatchedReasonFilter($inner, (array) $values); + continue; + } + $inner->whereIn($key, $values); + } + if (trim($orderNo) !== '') { + $inner->where('online_order_no', 'like', '%' . addcslashes(trim($orderNo), '%_\\') . '%'); + } + + $outer = DB::connection($connection) + ->query() + ->fromSub($inner, 'facet_rows'); + if ($remarkIndexes !== []) { + $outer->whereIn('reason_index', array_values(array_unique($remarkIndexes))); + } + if ($wantDifference !== $wantNoDifference) { + $effective = 'CASE WHEN remark IN (' + . implode(', ', array_map(static fn (string $mark): string => "'" . $mark . "'", $basisMarks)) + . ') AND reason_index = 0 THEN 0 ELSE base_difference END'; + $outer->whereRaw('ABS(' . $effective . ')' . ($wantDifference ? ' > 0.005' : ' <= 0.005')); + } + + $rows = $outer + ->select(['platform', 'store_name', 'match_status', 'remark', 'reason_index', 'base_difference']) + ->selectRaw('COUNT(*) AS total') + ->groupBy(['platform', 'store_name', 'match_status', 'remark', 'reason_index', 'base_difference']) + ->get(); + + $counts = [ + 'platform' => [], + 'store_name' => [], + 'match_status' => [], + 'remark' => [], + 'unmatched_reason' => [], + 'difference_state' => [], + ]; + $wanted = array_fill_keys($columns, true); + foreach ($rows as $row) { + $total = (int) ($row->total ?? 0); + $platform = (string) ($row->platform ?? ''); + $store = (string) ($row->store_name ?? ''); + $status = (string) ($row->match_status ?? ''); + $rawRemark = trim((string) ($row->remark ?? '')); + $reasonIndex = (int) ($row->reason_index ?? 0); + $reasonLabel = $reasonIndex > 0 ? ($labels[$reasonIndex - 1] ?? null) : null; + + if (isset($wanted['platform']) && $platform !== '') { + $counts['platform'][$platform] = ($counts['platform'][$platform] ?? 0) + $total; + } + if (isset($wanted['store_name']) && $store !== '') { + $counts['store_name'][$store] = ($counts['store_name'][$store] ?? 0) + $total; + } + if (isset($wanted['match_status']) && $status !== '') { + $counts['match_status'][$status] = ($counts['match_status'][$status] ?? 0) + $total; + } + if (isset($wanted['remark']) && $reasonLabel !== null) { + $counts['remark'][$reasonLabel] = ($counts['remark'][$reasonLabel] ?? 0) + $total; + } + if (isset($wanted['unmatched_reason'])) { + $unmatchedReason = ($status === '未匹配' && $rawRemark !== '') + ? $rawRemark + : (in_array($rawRemark, $basisMarks, true) ? $rawRemark : null); + if ($unmatchedReason !== null) { + $counts['unmatched_reason'][$unmatchedReason] = ($counts['unmatched_reason'][$unmatchedReason] ?? 0) + $total; + } + } + if (isset($wanted['difference_state'])) { + $difference = (float) ($row->base_difference ?? 0); + if ($reasonIndex === 0 && in_array($rawRemark, $basisMarks, true)) { + $difference = 0.0; + } + $differenceLabel = abs($difference) > 0.005 ? '有差额' : '无差额'; + $counts['difference_state'][$differenceLabel] = ($counts['difference_state'][$differenceLabel] ?? 0) + $total; + } + } + + return $counts; + } + /** * 单个筛选项的可选值与行数:应用除该筛选项以外的所有条件。 * @@ -1676,23 +1889,24 @@ class Pages extends Controller $query->where('online_order_no', 'like', '%' . addcslashes($orderNo, '%_\\') . '%'); } - // 差额异常备注联动:5 条原因一次查询算完(原来是 5 次全表 count,下拉要等 1 秒多) - $differenceCounts = []; - $differenceLabels = array_keys(self::receiptDifferenceRemarkConditions()); - if ($column === 'remark') { - $expressions = []; - foreach (array_values(self::receiptDifferenceRemarkConditions()) as $index => $condition) { - $expressions[] = 'SUM(CASE WHEN (' . $condition . ') THEN 1 ELSE 0 END) as c' . $index; - } - $row = (clone $query)->selectRaw(implode(', ', $expressions))->first(); - foreach ($differenceLabels as $index => $label) { - $differenceCounts[$label] = (int) ($row->{'c' . $index} ?? 0); - } - } - $counts = []; - // 未匹配原因是页面级判定(只统计未匹配行,按库里的 remark 分组) - if ($column === 'unmatched_reason') { + if ($column === 'remark') { + // 一行只按优先级命中一次,再按序号分组,避免 18 条规则各跑一遍全表。 + $indexSql = self::receiptDifferenceRemarkIndexSql(); + $rows = (clone $query) + ->selectRaw($indexSql . ' AS reason_index') + ->selectRaw('COUNT(*) AS total') + ->groupByRaw('reason_index') + ->pluck('total', 'reason_index'); + $labels = self::receiptDifferenceRemarkLabels(); + foreach ($rows as $index => $total) { + $label = $labels[(int) $index - 1] ?? null; + if ($label !== null && (int) $total > 0) { + $counts[$label] = (int) $total; + } + } + } elseif ($column === 'unmatched_reason') { + // 未匹配原因是页面级判定(只统计未匹配行,按库里的 remark 分组) $base = clone $query; $rows = $query->where('match_status', '未匹配') ->select('remark') @@ -1711,8 +1925,7 @@ class Pages extends Controller $counts[$basisMark] = (int) $marker; } } - } elseif ($column !== 'remark') { - // 差额异常备注是页面级判定,不再按库里的标注列分组 + } else { $rows = $query->select($column) ->selectRaw('count(*) as total') ->whereNotNull($column) @@ -1723,11 +1936,6 @@ class Pages extends Controller $counts[(string) $value] = (int) $total; } } - foreach ($differenceCounts as $label => $total) { - if ((int) $total > 0) { - $counts[$label] = (int) $total; - } - } $ordered = array_values(array_intersect($order, array_keys($counts))); $rest = array_values(array_diff(array_keys($counts), $ordered)); diff --git a/resources/views/business/pages/partials/directory-table.blade.php b/resources/views/business/pages/partials/directory-table.blade.php index a198e623..c2c05531 100644 --- a/resources/views/business/pages/partials/directory-table.blade.php +++ b/resources/views/business/pages/partials/directory-table.blade.php @@ -1896,13 +1896,17 @@ } function refresh() { + widgets.forEach(function (widget) { widget.setLoading(true); }); window.fetch(endpoint + '?' + currentParams().toString(), { headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' }, credentials: 'same-origin' }).then(function (response) { return response.ok ? response.json() : null; }).then(function (data) { - if (!data || !data.facets) { return; } + if (!data || !data.facets) { + widgets.forEach(function (widget) { widget.setLoading(false); }); + return; + } widgets.forEach(function (widget) { var facet = data.facets[widget.root.getAttribute('data-name')]; if (!facet || !facet.values) { return; } @@ -1912,8 +1916,10 @@ }); widget.setOptions(options, facet.counts || {}); }); + widgets.forEach(function (widget) { widget.setLoading(false); }); }).catch(function () { // 联动统计失败时保留原有选项,不影响筛选本身。 + widgets.forEach(function (widget) { widget.setLoading(false); }); }); } @@ -1942,7 +1948,8 @@ } }); } - schedule(); + // 首次加载立即取联动数量;只有勾选变化时才做 250ms 防抖。 + refresh(); })();