供应商对账:增加发货日期范围筛选 (#402)

内部厂家端和厂家门户增加日期面板与近7天、本月、上月、全部日期快捷筛选。
This commit is contained in:
renshen 2026-10-20 11:00:43 +08:00
parent 21b29d06eb
commit 145a62c397
3 changed files with 154 additions and 6 deletions

View File

@ -47,6 +47,8 @@
.supplier-reconciliation-page .sr-return-table { min-width: 1420px; }
.supplier-reconciliation-page .sr-filter { display: grid; grid-template-columns: minmax(220px, 1.6fr) repeat(2, minmax(135px, .8fr)) minmax(150px, 1fr) minmax(125px, .75fr); gap: 10px 12px; align-items: end; padding: 12px; border: 1px solid #EFEAE0; border-radius: 8px; background: #FCFAF5; }
.supplier-reconciliation-page .sr-filter-actions { display: flex; flex-wrap: wrap; gap: 8px; grid-column: 1 / -1; }
.supplier-reconciliation-page .sr-date-presets { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; grid-column: 1 / -1; margin-top: -2px; }
.supplier-reconciliation-page .sr-date-presets > span { margin-right: 2px; color: var(--vip-content-muted, #595959); font-size: .75rem; font-weight: 600; }
@media (max-width: 960px) {
.supplier-reconciliation-page .sr-filter { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.supplier-reconciliation-page .sr-return-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@ -258,7 +260,8 @@
<form method="GET"
action="{{ route('business.pages.show', ['section' => $section['slug'], 'page' => $page['slug']]) }}"
class="sr-filter"
aria-label="查询退货明细">
aria-label="查询退货明细"
data-return-filter-form>
<input type="hidden" name="supplier" value="{{ $selectedSupplier }}">
<label class="sr-field"><span>关键字</span>
<input type="text" name="return_keyword"
@ -267,10 +270,18 @@
placeholder="条形码 / 商品名称 / 供应商条码 / 配货单号 / 快递单号">
</label>
<label class="sr-field"><span>发货日期起</span>
<input type="date" name="return_date_from" value="{{ $returnPanel['filters']['date_from'] }}">
<input type="date"
id="business-return-date-from"
name="return_date_from"
value="{{ $returnPanel['filters']['date_from'] }}"
title="点击选择开始日期">
</label>
<label class="sr-field"><span>发货日期止</span>
<input type="date" name="return_date_to" value="{{ $returnPanel['filters']['date_to'] }}">
<input type="date"
id="business-return-date-to"
name="return_date_to"
value="{{ $returnPanel['filters']['date_to'] }}"
title="点击选择结束日期">
</label>
<label class="sr-field"><span>仓库名称</span>
<select name="return_warehouse">
@ -288,6 +299,13 @@
<option value="disputed" @selected($returnPanel['filters']['status'] === 'disputed')>异议中</option>
</select>
</label>
<div class="sr-date-presets" role="group" aria-label="快捷发货日期">
<span>快捷日期</span>
<button type="button" class="sr-button is-small" data-return-date-range="last-7">近 7 天</button>
<button type="button" class="sr-button is-small" data-return-date-range="this-month">本月</button>
<button type="button" class="sr-button is-small" data-return-date-range="last-month">上月</button>
<button type="button" class="sr-button is-small" data-return-date-range="all">全部日期</button>
</div>
<div class="sr-filter-actions">
<button type="submit" class="sr-button is-primary">查询</button>
<a class="sr-button"
@ -424,4 +442,58 @@
</div>
</div>
@endif
<script>
(() => {
const form = document.querySelector('[data-return-filter-form]');
if (!form) {
return;
}
const from = form.querySelector('#business-return-date-from');
const to = form.querySelector('#business-return-date-to');
const iso = (date) => [
date.getFullYear(),
String(date.getMonth() + 1).padStart(2, '0'),
String(date.getDate()).padStart(2, '0'),
].join('-');
[from, to].forEach((input) => {
input?.addEventListener('click', () => {
if (typeof input.showPicker === 'function') {
try {
input.showPicker();
} catch (error) {
// 浏览器已在日期面板中打开时忽略。
}
}
});
});
form.querySelectorAll('[data-return-date-range]').forEach((button) => {
button.addEventListener('click', () => {
const today = new Date();
const kind = button.dataset.returnDateRange;
if (kind === 'all') {
from.value = '';
to.value = '';
} else if (kind === 'this-month') {
from.value = iso(new Date(today.getFullYear(), today.getMonth(), 1));
to.value = iso(today);
} else if (kind === 'last-month') {
from.value = iso(new Date(today.getFullYear(), today.getMonth() - 1, 1));
to.value = iso(new Date(today.getFullYear(), today.getMonth(), 0));
} else if (kind === 'last-7') {
const start = new Date(today);
start.setDate(start.getDate() - 6);
from.value = iso(start);
to.value = iso(today);
}
form.submit();
});
});
})();
</script>
</div>

View File

@ -45,6 +45,8 @@
.supplier-portal-page .sp-return-table { min-width: 1420px; }
.supplier-portal-page .sp-filter { display: grid; grid-template-columns: minmax(220px, 1.6fr) repeat(2, minmax(135px, .8fr)) minmax(150px, 1fr) minmax(125px, .75fr); gap: 10px 12px; align-items: end; padding: 12px; border: 1px solid #EFEAE0; border-radius: 8px; background: #FCFAF5; }
.supplier-portal-page .sp-filter-actions { display: flex; flex-wrap: wrap; gap: 8px; grid-column: 1 / -1; }
.supplier-portal-page .sp-date-presets { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; grid-column: 1 / -1; margin-top: -2px; }
.supplier-portal-page .sp-date-presets > span { margin-right: 2px; color: var(--vip-content-muted, #595959); font-size: .75rem; font-weight: 600; }
.supplier-portal-page .sp-pagination { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; color: var(--vip-content-muted, #595959); font-size: .8125rem; }
.supplier-portal-page .sp-tag { display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: 4px; background: #EFEAE0; color: #595959; font-size: .75rem; white-space: nowrap; }
.supplier-portal-page .sp-tag.is-match { background: #ECF4EC; color: #3F7A46; }
@ -145,7 +147,8 @@
<form method="GET"
action="{{ route('portal.supplier-reconciliation.index') }}"
class="sp-filter"
aria-label="查询退货明细">
aria-label="查询退货明细"
data-return-filter-form>
<label class="sp-field"><span>关键字</span>
<input type="text" name="return_keyword"
value="{{ $returnPanel['filters']['keyword'] }}"
@ -153,10 +156,18 @@
placeholder="条形码 / 商品名称 / 供应商条码 / 配货单号 / 快递单号">
</label>
<label class="sp-field"><span>发货日期起</span>
<input type="date" name="return_date_from" value="{{ $returnPanel['filters']['date_from'] }}">
<input type="date"
id="portal-return-date-from"
name="return_date_from"
value="{{ $returnPanel['filters']['date_from'] }}"
title="点击选择开始日期">
</label>
<label class="sp-field"><span>发货日期止</span>
<input type="date" name="return_date_to" value="{{ $returnPanel['filters']['date_to'] }}">
<input type="date"
id="portal-return-date-to"
name="return_date_to"
value="{{ $returnPanel['filters']['date_to'] }}"
title="点击选择结束日期">
</label>
<label class="sp-field"><span>仓库名称</span>
<select name="return_warehouse">
@ -174,6 +185,13 @@
<option value="disputed" @selected($returnPanel['filters']['status'] === 'disputed')>异议中</option>
</select>
</label>
<div class="sp-date-presets" role="group" aria-label="快捷发货日期">
<span>快捷日期</span>
<button type="button" class="sp-button is-small" data-return-date-range="last-7">近 7 天</button>
<button type="button" class="sp-button is-small" data-return-date-range="this-month">本月</button>
<button type="button" class="sp-button is-small" data-return-date-range="last-month">上月</button>
<button type="button" class="sp-button is-small" data-return-date-range="all">全部日期</button>
</div>
<div class="sp-filter-actions">
<button type="submit" class="sp-button is-primary">查询</button>
<a class="sp-button" href="{{ route('portal.supplier-reconciliation.index') }}">重置</a>
@ -347,5 +365,58 @@
@endif
</div>
</div>
<script>
(() => {
const form = document.querySelector('[data-return-filter-form]');
if (!form) {
return;
}
const from = form.querySelector('#portal-return-date-from');
const to = form.querySelector('#portal-return-date-to');
const iso = (date) => [
date.getFullYear(),
String(date.getMonth() + 1).padStart(2, '0'),
String(date.getDate()).padStart(2, '0'),
].join('-');
[from, to].forEach((input) => {
input?.addEventListener('click', () => {
if (typeof input.showPicker === 'function') {
try {
input.showPicker();
} catch (error) {
// 浏览器已在日期面板中打开时忽略。
}
}
});
});
form.querySelectorAll('[data-return-date-range]').forEach((button) => {
button.addEventListener('click', () => {
const today = new Date();
const kind = button.dataset.returnDateRange;
if (kind === 'all') {
from.value = '';
to.value = '';
} else if (kind === 'this-month') {
from.value = iso(new Date(today.getFullYear(), today.getMonth(), 1));
to.value = iso(today);
} else if (kind === 'last-month') {
from.value = iso(new Date(today.getFullYear(), today.getMonth() - 1, 1));
to.value = iso(new Date(today.getFullYear(), today.getMonth(), 0));
} else if (kind === 'last-7') {
const start = new Date(today);
start.setDate(start.getDate() - 6);
from.value = iso(start);
to.value = iso(today);
}
form.submit();
});
});
})();
</script>
</x-slot>
</x-layouts.portal>

View File

@ -238,6 +238,8 @@ class SupplierReconciliationTest extends FeatureTestCase
->assertDontSeeText('OTHER-SUPPLIER-RETURN')
->assertDontSeeText('鸣飞家具')
->assertDontSee('supplier-name-options', false)
->assertSee('id="portal-return-date-from"', false)
->assertSee('data-return-date-range="last-month"', false)
->assertDontSeeText('预估单价');
$this->loginAs($vendor)->get($portalUrl . '?return_page=2')
@ -526,6 +528,9 @@ class SupplierReconciliationTest extends FeatureTestCase
$this->loginAs()->get(route('business.pages.show', $filters))
->assertOk()
->assertSeeText('当前筛选 19 件,退货金额 ¥1,900.00')
->assertSee('value="2026-09-20"', false)
->assertSee('value="2026-09-21"', false)
->assertSee('data-return-date-range="last-month"', false)
->assertSeeText('MATCH-01')
->assertDontSeeText('MATCH-20')
->assertDontSeeText('OTHER-01')