修复共享快照处理中状态反馈 #46
@ -13,6 +13,7 @@ use Illuminate\Routing\Controller;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Modules\EcommerceFinance\Exceptions\UpstreamSnapshotPendingException;
|
||||
use Modules\EcommerceFinance\Repositories\AlibabaBillRepository;
|
||||
use Modules\EcommerceFinance\Repositories\EdgeBandingRepository;
|
||||
use Modules\EcommerceFinance\Repositories\InventoryRepository;
|
||||
@ -248,6 +249,7 @@ class Pages extends Controller
|
||||
'platform' => $tab,
|
||||
'balances' => collect(),
|
||||
'error' => null,
|
||||
'pending' => false,
|
||||
];
|
||||
|
||||
if (! in_array($tab, ['taobao-alipay', 'pinduoduo'], true)) {
|
||||
@ -282,6 +284,9 @@ class Pages extends Controller
|
||||
$pageSize,
|
||||
),
|
||||
);
|
||||
} catch (UpstreamSnapshotPendingException $exception) {
|
||||
$content['pending'] = true;
|
||||
$result = ['rows' => [], 'total' => 0];
|
||||
} catch (ServiceUnavailableHttpException $exception) {
|
||||
$content['error'] = $exception->getMessage();
|
||||
$result = ['rows' => [], 'total' => 0];
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\EcommerceFinance\Exceptions;
|
||||
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
|
||||
class UpstreamSnapshotPendingException extends ServiceUnavailableHttpException
|
||||
{
|
||||
public function __construct(int $retryAfter = 15)
|
||||
{
|
||||
parent::__construct(
|
||||
$retryAfter,
|
||||
'数据同步请求已登记,后台正在准备首份共享数据。'
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ use Illuminate\Contracts\Cache\Repository;
|
||||
use Illuminate\Contracts\Cache\Lock;
|
||||
use Illuminate\Contracts\Cache\LockTimeoutException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Modules\EcommerceFinance\Exceptions\UpstreamSnapshotPendingException;
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
use Throwable;
|
||||
|
||||
@ -102,10 +103,7 @@ class UpstreamQueryCache
|
||||
$this->register($scope, $parameters, true);
|
||||
|
||||
if (! (bool) config('upstreams.snapshots.allow_inline_refresh', false)) {
|
||||
throw new ServiceUnavailableHttpException(
|
||||
15,
|
||||
'数据同步请求已登记,后台正在准备首份共享数据,请稍后刷新。'
|
||||
);
|
||||
throw new UpstreamSnapshotPendingException();
|
||||
}
|
||||
|
||||
$resolved = $this->resolve($scope, $parameters, $resolver, false);
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
.marketing-balance-pagination .page-item.disabled .page-link { color: #595959; cursor: not-allowed; }
|
||||
.marketing-balance-pagination div.lg\:flex > div:first-child { display: none !important; }
|
||||
.marketing-balance-pagination div.lg\:flex { justify-content: center; }
|
||||
.marketing-balance-status { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; border: 1px solid var(--vip-border, #D8D2C7); border-radius: 12px; background: var(--vip-content-accent-soft, #F7F0DE); padding: 12px 14px; color: #513E21; font-size: 0.875rem; line-height: 1.5; }
|
||||
.marketing-balance-status .material-icons-outlined { flex: 0 0 auto; color: var(--vip-content-accent-dark, #856632); font-size: 14px; }
|
||||
</style>
|
||||
|
||||
<div class="biz-card-head">
|
||||
@ -71,6 +73,11 @@
|
||||
|
||||
@if (! empty($error))
|
||||
<div class="biz-alert biz-alert-error" role="alert">{{ $error }}</div>
|
||||
@elseif (! empty($pending))
|
||||
<div class="marketing-balance-status" role="status" aria-live="polite" data-marketing-balance-pending>
|
||||
<span class="material-icons-outlined" aria-hidden="true">sync</span>
|
||||
<span>同步请求已进入后台队列,页面会自动检查首份共享数据,无需重复操作。</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($supportsBalances)
|
||||
@ -104,3 +111,32 @@
|
||||
<div>该平台余额数据表尚未配置。</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (! empty($pending))
|
||||
<script>
|
||||
(function () {
|
||||
var key = 'caiwu-marketing-balance-pending:' + window.location.pathname + window.location.search;
|
||||
var attempts = Number(window.sessionStorage.getItem(key) || 0);
|
||||
var maximumAttempts = 10;
|
||||
|
||||
if (attempts >= maximumAttempts) {
|
||||
var status = document.querySelector('[data-marketing-balance-pending] span:last-child');
|
||||
|
||||
if (status) {
|
||||
status.textContent = '后台仍在处理首份共享数据,请稍后手动刷新;无需重复提交查询。';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.sessionStorage.setItem(key, String(attempts + 1));
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 30000);
|
||||
}());
|
||||
</script>
|
||||
@elseif ($supportsBalances)
|
||||
<script>
|
||||
window.sessionStorage.removeItem('caiwu-marketing-balance-pending:' + window.location.pathname + window.location.search);
|
||||
</script>
|
||||
@endif
|
||||
|
||||
@ -4,6 +4,7 @@ namespace Tests\Feature\Business;
|
||||
|
||||
use App\Models\Auth\Permission;
|
||||
use Mockery;
|
||||
use Modules\EcommerceFinance\Exceptions\UpstreamSnapshotPendingException;
|
||||
use Modules\EcommerceFinance\Repositories\JdWalletBillRepository;
|
||||
use Modules\EcommerceFinance\Repositories\PinduoduoSpreadBillRepository;
|
||||
use Modules\EcommerceFinance\Repositories\TmallTaobaoSpreadBillRepository;
|
||||
@ -196,6 +197,38 @@ class MarketingAccountBillsTabsTest extends FeatureTestCase
|
||||
->assertSessionHas('error', '首份共享快照正在准备,系统已登记刷新请求;请稍后刷新页面后再导出。');
|
||||
}
|
||||
|
||||
public function testMarketingAccountBalanceColdStartShowsProcessingStateAndAutomaticCheck(): void
|
||||
{
|
||||
$this->allowMarketingAccountBalancePage();
|
||||
$cache = Mockery::mock(UpstreamQueryCache::class);
|
||||
$cache->shouldReceive('remember')
|
||||
->once()
|
||||
->withArgs(fn (string $scope): bool => $scope === 'taobao-alipay-bills.list')
|
||||
->andThrow(new UpstreamSnapshotPendingException());
|
||||
$cache->shouldReceive('remember')
|
||||
->once()
|
||||
->withArgs(fn (string $scope): bool => $scope === 'taobao-alipay-bills.options')
|
||||
->andReturn([]);
|
||||
|
||||
$factory = Mockery::mock(UpstreamQueryCacheFactory::class);
|
||||
$factory->shouldReceive('forSource')->once()->with('jiansun')->andReturn($cache);
|
||||
|
||||
$this->app->instance(UpstreamQueryCacheFactory::class, $factory);
|
||||
$this->app->instance(TmallTaobaoSpreadBillRepository::class, Mockery::mock(TmallTaobaoSpreadBillRepository::class));
|
||||
|
||||
$this->loginAs()
|
||||
->get(route('business.pages.show', [
|
||||
'section' => 'billing-transactions',
|
||||
'page' => 'marketing-account-balance',
|
||||
'tab' => 'taobao-alipay',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSeeText('同步请求已进入后台队列,页面会自动检查首份共享数据,无需重复操作。')
|
||||
->assertSee('data-marketing-balance-pending', false)
|
||||
->assertSee('window.location.reload()', false)
|
||||
->assertDontSee('<div class="biz-alert biz-alert-error" role="alert">', false);
|
||||
}
|
||||
|
||||
public function testMarketingAccountBalanceExportUnexpectedFailureReturnsRedactedRedirect(): void
|
||||
{
|
||||
$this->allowMarketingAccountBalancePage();
|
||||
|
||||
@ -5,6 +5,7 @@ namespace Tests\Unit\EcommerceFinance;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use InvalidArgumentException;
|
||||
use Modules\EcommerceFinance\Exceptions\UpstreamSnapshotPendingException;
|
||||
use Modules\EcommerceFinance\Services\UpstreamOdbcConnection;
|
||||
use Modules\EcommerceFinance\Services\UpstreamQueryCacheFactory;
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
@ -103,9 +104,10 @@ class UpstreamQueryCacheTest extends TestCase
|
||||
return ['total' => 1];
|
||||
});
|
||||
$this->fail('页面冷查询不应直接访问上游数据库。');
|
||||
} catch (ServiceUnavailableHttpException $exception) {
|
||||
} catch (UpstreamSnapshotPendingException $exception) {
|
||||
$this->assertSame(0, $calls);
|
||||
$this->assertStringContainsString('后台正在准备', $exception->getMessage());
|
||||
$this->assertSame(15, $exception->getHeaders()['Retry-After']);
|
||||
$this->assertNotEmpty(Cache::get('source_a:snapshots:active:v2'));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user