快递应付:左侧增加快递报价入口并打开四个页面 #309
@ -360,6 +360,13 @@ class Pages extends Controller
|
||||
|
||||
abort_if(empty($pageConfig), 404);
|
||||
|
||||
if ($section === 'courier-payables' && $page === 'courier-quote') {
|
||||
abort_if(empty($pageConfig['children']), 403, '当前账号没有可访问的快递报价页面。');
|
||||
abort_if($tab !== null, 404);
|
||||
|
||||
return view('business.pages.show', $this->viewData($sectionConfig, $pageConfig));
|
||||
}
|
||||
|
||||
if (! empty($pageConfig['children']) && empty($pageConfig['tabs'])) {
|
||||
return $this->redirectToPage($sectionConfig, $pageConfig['children'][0]);
|
||||
}
|
||||
|
||||
@ -119,6 +119,10 @@ class ShowInAdmin
|
||||
$order = ($sectionIndex + 1) * 10;
|
||||
|
||||
if (empty($pages) || in_array($section['slug'], self::WORKSPACE_SECTION_SLUGS, true)) {
|
||||
$quoteDirectory = $section['slug'] === 'courier-payables'
|
||||
? collect($pages)->firstWhere('slug', 'courier-quote')
|
||||
: null;
|
||||
$quoteSlugs = array_merge(['courier-quote'], array_column($quoteDirectory['children'] ?? [], 'slug'));
|
||||
$menu->route(
|
||||
'business.pages.show',
|
||||
$section['title'],
|
||||
@ -126,10 +130,26 @@ class ShowInAdmin
|
||||
$order,
|
||||
[
|
||||
'icon' => $section['icon'],
|
||||
'active' => fn () => request()->route('section') === $section['slug'],
|
||||
'active' => fn () => request()->route('section') === $section['slug']
|
||||
&& (! $quoteDirectory || ! in_array(request()->route('page'), $quoteSlugs, true)),
|
||||
]
|
||||
);
|
||||
|
||||
if (! empty($quoteDirectory['children'])) {
|
||||
$menu->route(
|
||||
'business.pages.show',
|
||||
$quoteDirectory['title'],
|
||||
['section' => $section['slug'], 'page' => $quoteDirectory['slug']],
|
||||
$order + 1,
|
||||
[
|
||||
'icon' => '',
|
||||
'class' => 'ltr:ml-8 rtl:mr-8',
|
||||
'active' => fn () => request()->route('section') === $section['slug']
|
||||
&& in_array(request()->route('page'), $quoteSlugs, true),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -1,30 +1,17 @@
|
||||
@php
|
||||
$courierSection = collect(\App\Utilities\SidebarPermissions::navigationFor(user()))->firstWhere('slug', 'courier-payables');
|
||||
$courierPages = $courierSection['pages'] ?? [];
|
||||
$isQuoteWorkspace = ($page['slug'] ?? null) === 'courier-quote';
|
||||
$courierPages = $isQuoteWorkspace
|
||||
? ($page['children'] ?? [])
|
||||
: array_values(array_filter($courierSection['pages'] ?? [], static fn (array $item) => $item['slug'] !== 'courier-quote'));
|
||||
@endphp
|
||||
<div data-courier-final>
|
||||
<nav class="business-tab-bar courier-final-tabs" aria-label="快递应付子功能">
|
||||
<div data-courier-final @if ($isQuoteWorkspace) data-courier-quote-workspace @endif>
|
||||
<nav class="business-tab-bar courier-final-tabs" aria-label="{{ $isQuoteWorkspace ? $page['title'] : '快递应付子功能' }}">
|
||||
@foreach ($courierPages as $item)
|
||||
@if (!empty($item['children']))
|
||||
<button type="button" class="business-tab-link" data-courier-group="{{ $item['slug'] }}"
|
||||
aria-expanded="false" aria-controls="courier-group-{{ $item['slug'] }}">{{ $item['title'] }}</button>
|
||||
@else
|
||||
<a class="business-tab-link" data-courier-tab="{{ $item['slug'] }}"
|
||||
href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => $item['slug']]) }}">{{ $item['title'] }}</a>
|
||||
@endif
|
||||
<a class="business-tab-link" data-courier-tab="{{ $item['slug'] }}"
|
||||
href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => $item['slug']]) }}">{{ $item['title'] }}</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
@foreach ($courierPages as $item)
|
||||
@if (!empty($item['children']))
|
||||
<nav class="business-tab-bar courier-final-tabs courier-final-subtabs" id="courier-group-{{ $item['slug'] }}"
|
||||
aria-label="{{ $item['title'] }}子功能" data-courier-subtabs="{{ $item['slug'] }}" hidden>
|
||||
@foreach ($item['children'] as $child)
|
||||
<a class="business-tab-link" data-courier-tab="{{ $child['slug'] }}" data-courier-parent="{{ $item['slug'] }}"
|
||||
href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => $child['slug']]) }}">{{ $child['title'] }}</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
@endif
|
||||
@endforeach
|
||||
<div role="status" aria-live="polite" data-courier-status></div>
|
||||
<button type="button" class="business-tab-link" data-courier-retry hidden>重新加载</button>
|
||||
@if (empty($courierPages))
|
||||
@ -35,10 +22,7 @@
|
||||
<style>
|
||||
.courier-final-tabs { flex-wrap:wrap; gap:4px 16px; min-height:34px; padding:0 16px; margin-bottom:12px; }
|
||||
.courier-final-tabs .business-tab-link { min-height:34px; font-size:12px; color:var(--vip-content-muted, #595959); }
|
||||
.courier-final-tabs button.business-tab-link { border:0; background:transparent; padding:0; font-family:inherit; cursor:pointer; }
|
||||
.courier-final-tabs .business-tab-link:focus-visible { outline:2px solid var(--vip-content-accent-dark, #856632); outline-offset:3px; }
|
||||
.courier-final-subtabs[hidden] { display:none; }
|
||||
.courier-final-subtabs { border:0; border-bottom:1px solid var(--vip-border, #D8D2C7); border-radius:0; box-shadow:none; }
|
||||
.courier-final-tabs .is-active { color:var(--vip-content-accent-dark, #856632); }
|
||||
@media (max-width:640px) { .courier-final-tabs { flex-wrap:nowrap; } }
|
||||
[data-courier-frames] iframe { width:100%; height:calc(100vh - 260px); min-height:400px; border:0; }
|
||||
@ -51,9 +35,6 @@
|
||||
const root = document.querySelector('[data-courier-final]');
|
||||
if (!root) return;
|
||||
const links = [...root.querySelectorAll('[data-courier-tab]')];
|
||||
const groups = [...root.querySelectorAll('[data-courier-group]')];
|
||||
const submenus = [...root.querySelectorAll('[data-courier-subtabs]')];
|
||||
const groupSelections = new Map();
|
||||
const frames = new Map();
|
||||
const status = root.querySelector('[data-courier-status]');
|
||||
const retry = root.querySelector('[data-courier-retry]');
|
||||
@ -62,14 +43,6 @@
|
||||
if (!link) return;
|
||||
selected = link;
|
||||
retry.hidden = true;
|
||||
const parent = link.dataset.courierParent;
|
||||
if (parent) groupSelections.set(parent, link);
|
||||
groups.forEach(group => {
|
||||
const active = group.dataset.courierGroup === parent;
|
||||
group.classList.toggle('is-active', active);
|
||||
group.setAttribute('aria-expanded', String(active));
|
||||
});
|
||||
submenus.forEach(menu => menu.hidden = menu.dataset.courierSubtabs !== parent);
|
||||
links.forEach(item => {
|
||||
item.classList.toggle('is-active', item === link);
|
||||
if (item === link) item.setAttribute('aria-current', 'page');
|
||||
@ -125,15 +98,10 @@
|
||||
if (event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
|
||||
event.preventDefault(); select(link);
|
||||
}));
|
||||
const groupTarget = group => group && (groupSelections.get(group.dataset.courierGroup)
|
||||
|| links.find(link => link.dataset.courierParent === group.dataset.courierGroup));
|
||||
groups.forEach(group => group.addEventListener('click', () => select(groupTarget(group))));
|
||||
retry.addEventListener('click', () => select(selected, false, true));
|
||||
const restore = () => {
|
||||
const view = new URL(location.href).searchParams.get('view');
|
||||
select(links.find(link => link.dataset.courierTab === view)
|
||||
|| groupTarget(groups.find(group => group.dataset.courierGroup === view))
|
||||
|| groupTarget(groups[0]) || links[0], false);
|
||||
select(links.find(link => link.dataset.courierTab === view) || links[0], false);
|
||||
};
|
||||
window.addEventListener('popstate', restore);
|
||||
restore();
|
||||
|
||||
@ -647,7 +647,7 @@
|
||||
|
||||
@if (!empty($payablesFinal))
|
||||
@include('business.pages.partials.final-dataset-table', ['payablesFinal' => $payablesFinal])
|
||||
@elseif ($section['slug'] === 'courier-payables' && empty($page))
|
||||
@elseif ($section['slug'] === 'courier-payables' && (empty($page) || $page['slug'] === 'courier-quote'))
|
||||
@include('business.pages.courier-payables.final-workspace')
|
||||
@elseif ($sectionView)
|
||||
@include($sectionView)
|
||||
|
||||
@ -201,6 +201,43 @@ class QuoteManagementPageTest extends FeatureTestCase
|
||||
->assertSee('data-reverse-rate-body', false);
|
||||
}
|
||||
|
||||
public function testCourierQuoteSidebarEntryOpensFourWorkspacePagesAndKeepsOtherPayablePages(): void
|
||||
{
|
||||
$subject = 'user_' . $this->user->id;
|
||||
$this->user->roles()->sync([
|
||||
\App\Models\Auth\Role::where('name', 'admin')->firstOrFail()->id,
|
||||
]);
|
||||
setting()->set('system.sidebar_permissions', [
|
||||
'configured' => [$subject],
|
||||
'subjects' => [$subject => ['courier-payables']],
|
||||
]);
|
||||
setting()->save();
|
||||
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
||||
|
||||
$response = $this->loginAs()->get(route('business.pages.show', ['section' => 'courier-payables']))
|
||||
->assertOk()
|
||||
->assertSeeText('快递报价')
|
||||
->assertSee(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-quote']), false)
|
||||
->assertSee('data-courier-tab="freight-reconciliation"', false)
|
||||
->assertSee('data-courier-tab="shipping-data"', false)
|
||||
->assertDontSee('data-courier-group="courier-quote"', false);
|
||||
|
||||
foreach (['quote-management', 'courier-information', 'agreement-signing', 'courier-surcharge'] as $page) {
|
||||
$response->assertDontSee('data-courier-tab="' . $page . '"', false);
|
||||
}
|
||||
|
||||
$response = $this->get(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-quote']))
|
||||
->assertOk()
|
||||
->assertSee('data-courier-quote-workspace', false)
|
||||
->assertDontSee('data-courier-tab="freight-reconciliation"', false)
|
||||
->assertDontSee('data-courier-tab="shipping-data"', false);
|
||||
|
||||
foreach (['quote-management', 'courier-information', 'agreement-signing', 'courier-surcharge'] as $page) {
|
||||
$response->assertSee(route('business.pages.show', ['section' => 'courier-payables', 'page' => $page]), false)
|
||||
->assertSee('data-courier-tab="' . $page . '"', false);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCourierQuoteDirectoryKeepsPageLabelsAndExactPermissions(): void
|
||||
{
|
||||
setting()->set('navigation.titles', [
|
||||
@ -228,13 +265,18 @@ class QuoteManagementPageTest extends FeatureTestCase
|
||||
|
||||
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
||||
$this->loginAs()
|
||||
->get(route('business.pages.show', ['section' => 'courier-payables']))
|
||||
->get(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-quote']))
|
||||
->assertOk()
|
||||
->assertSee('data-courier-group="courier-quote"', false)
|
||||
->assertSeeText('快递报价')
|
||||
->assertSeeText('快递报价单')
|
||||
->assertSee('data-courier-tab="courier-surcharge"', false)
|
||||
->assertDontSee('data-courier-tab="courier-information"', false)
|
||||
->assertDontSee('data-courier-tab="agreement-signing"', false);
|
||||
->assertSee(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'quote-management']), false)
|
||||
->assertSee(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-surcharge']), false)
|
||||
->assertDontSee(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-information']), false)
|
||||
->assertDontSee(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'agreement-signing']), false)
|
||||
->assertSee('data-courier-quote-workspace', false)
|
||||
->assertDontSee('data-courier-group="courier-quote"', false)
|
||||
->assertSee('data-courier-tab="quote-management"', false)
|
||||
->assertSee('data-courier-tab="courier-surcharge"', false);
|
||||
|
||||
try {
|
||||
$this->get(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-information']));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user