390 lines
28 KiB
PHP
390 lines
28 KiB
PHP
@php
|
||
$rows = $courierSurchargeSettlementRows ?? collect();
|
||
$filters = $courierSurchargeSettlementFilters ?? [];
|
||
$summary = $courierSurchargeSettlementSummary ?? ['count' => 0, 'settlement_amount' => 0];
|
||
$sync = $courierSurchargeSettlementSync ?? ['code' => 'unavailable', 'last_succeeded_at' => null];
|
||
$state = $courierSurchargeSettlementState ?? [];
|
||
$error = $courierSurchargeSettlementError ?? null;
|
||
$columns = [
|
||
['key' => 'courier_name', 'label' => '快递名称', 'fixed' => 'true'],
|
||
['key' => 'shipped_at', 'label' => '出库时间'],
|
||
['key' => 'waybill', 'label' => '单号'],
|
||
['key' => 'platform_product_id', 'label' => '平台商品ID'],
|
||
['key' => 'product_code', 'label' => '商品编码'],
|
||
['key' => 'shop_name', 'label' => '店铺名称'],
|
||
['key' => 'online_order_no', 'label' => '线上订单号'],
|
||
['key' => 'length', 'label' => '长'],
|
||
['key' => 'width', 'label' => '宽'],
|
||
['key' => 'height', 'label' => '高'],
|
||
['key' => 'volume', 'label' => '体积'],
|
||
['key' => 'inspection_type', 'label' => '查件类型'],
|
||
['key' => 'inspection_reason', 'label' => '查件原因'],
|
||
['key' => 'return_waybill_no', 'label' => '退回单号'],
|
||
['key' => 'settlement_weight', 'label' => '结算重量'],
|
||
['key' => 'settlement_amount', 'label' => '结算金额'],
|
||
['key' => 'surcharge_type', 'label' => '附加费类型', 'fixed' => 'end'],
|
||
];
|
||
$filterValue = static fn (string $key): string => trim((string) ($filters[$key] ?? ''));
|
||
$syncLabel = match ($sync['code'] ?? null) {
|
||
'fresh' => '最新',
|
||
'stale' => '稍有延迟',
|
||
'pending', 'initializing', 'syncing' => '同步中',
|
||
'failed', 'initial_failed' => '同步失败',
|
||
default => '不可用',
|
||
};
|
||
$emptyMessage = match (true) {
|
||
$error !== null => $error,
|
||
($sync['code'] ?? null) === 'pending' || ($sync['code'] ?? null) === 'syncing' => '镜像正在同步,完成后将自动显示附加费明细。',
|
||
($sync['code'] ?? null) === 'failed' || ($sync['code'] ?? null) === 'initial_failed' => '镜像同步失败,暂不展示不完整数据。',
|
||
default => '当前筛选条件没有匹配的附加费明细。',
|
||
};
|
||
$displayValue = static function (mixed $value, string $key): string {
|
||
if ($value === null || $value === '') {
|
||
return '—';
|
||
}
|
||
|
||
if ($key === 'settlement_amount' && is_numeric($value)) {
|
||
return number_format((float) $value, 2, '.', '');
|
||
}
|
||
|
||
return (string) $value;
|
||
};
|
||
@endphp
|
||
|
||
<section class="surcharge-settlement-page" aria-label="附加费结算">
|
||
<style>
|
||
.surcharge-settlement-page {
|
||
--settlement-ink: var(--vip-content-ink, #171717);
|
||
--settlement-muted: var(--vip-content-muted, #595959);
|
||
--settlement-accent: var(--vip-content-accent-dark, #856632);
|
||
--settlement-soft: var(--vip-content-accent-soft, #f7f0de);
|
||
--settlement-border: var(--vip-border, #d8d2c7);
|
||
display: grid;
|
||
gap: .65rem;
|
||
min-width: 0;
|
||
color: var(--settlement-ink);
|
||
font-family: "JetBrains Mono", "Microsoft YaHei", "PingFang SC", monospace;
|
||
font-size: .8125rem;
|
||
}
|
||
|
||
.surcharge-settlement-page *,
|
||
.surcharge-settlement-page *::before,
|
||
.surcharge-settlement-page *::after { box-sizing: border-box; }
|
||
.surcharge-settlement-page > * { min-width: 0; }
|
||
|
||
.settlement-notice {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: .65rem;
|
||
padding: .75rem 1rem;
|
||
border: 1px solid #d7c39d;
|
||
border-radius: .65rem;
|
||
background: #fffaf0;
|
||
color: #6a5129;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.settlement-notice .material-icons-outlined { color: var(--settlement-accent); font-size: 1.15rem; }
|
||
.settlement-notice strong { color: var(--settlement-ink); }
|
||
|
||
.settlement-summary {
|
||
display: grid;
|
||
grid-template-columns: 1.35fr repeat(3, minmax(8rem, 1fr));
|
||
overflow: hidden;
|
||
border: 1px solid var(--settlement-border);
|
||
border-radius: .75rem;
|
||
background: #fff;
|
||
}
|
||
|
||
.settlement-summary__intro,
|
||
.settlement-summary__metric { min-width: 0; padding: .55rem .9rem; }
|
||
.settlement-summary__intro { display: flex; align-items: center; gap: .6rem; }
|
||
.settlement-summary__icon { display: grid; flex: none; width: 1.9rem; height: 1.9rem; place-items: center; border-radius: .5rem; background: var(--settlement-soft); color: var(--settlement-accent); }
|
||
.settlement-summary__title { font-size: .875rem; font-weight: 700; }
|
||
.settlement-summary__subtitle { margin-top: .1rem; color: var(--settlement-muted); font-size: .68rem; }
|
||
.settlement-summary__metric { border-left: 1px solid var(--settlement-border); }
|
||
.settlement-summary__label { color: var(--settlement-muted); font-size: .68rem; }
|
||
.settlement-summary__value { margin-top: .15rem; font-size: .95rem; font-weight: 700; font-variant-numeric: tabular-nums; }
|
||
|
||
.settlement-filter-bar {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(10rem, 1fr));
|
||
gap: .45rem .6rem;
|
||
align-items: end;
|
||
padding: .55rem .9rem;
|
||
border: 1px solid var(--settlement-border);
|
||
border-radius: .75rem;
|
||
background: #fffdf8;
|
||
}
|
||
|
||
.settlement-field { display: grid; gap: .2rem; min-width: 0; }
|
||
.settlement-field[hidden] { display: none; }
|
||
.settlement-field label { color: var(--settlement-muted); font-size: .68rem; font-weight: 600; }
|
||
.settlement-field input,
|
||
.settlement-field select {
|
||
width: 100%;
|
||
height: 1.9rem;
|
||
min-width: 0;
|
||
padding: 0 .5rem;
|
||
border: 1px solid var(--settlement-border);
|
||
border-radius: .4rem;
|
||
background: #fff;
|
||
color: var(--settlement-ink);
|
||
font: inherit;
|
||
}
|
||
|
||
.settlement-field input:focus,
|
||
.settlement-field select:focus { border-color: var(--settlement-accent); outline: none; box-shadow: 0 0 0 3px rgba(133, 102, 50, .18); }
|
||
.settlement-actions { display: flex; flex-wrap: wrap; gap: .4rem; align-items: end; }
|
||
.settlement-filter-bar .settlement-actions { grid-column: 1 / -1; }
|
||
.settlement-button { display: inline-flex; align-items: center; justify-content: center; gap: .3rem; min-height: 1.9rem; padding: 0 .65rem; border: 1px solid var(--settlement-border); border-radius: .4rem; background: #fff; color: var(--settlement-ink); font: inherit; font-weight: 600; text-decoration: none; white-space: nowrap; cursor: pointer; }
|
||
.settlement-button--primary { border-color: var(--settlement-accent); background: var(--settlement-accent); color: #fff; }
|
||
.settlement-button .material-icons-outlined { font-size: .95rem; }
|
||
.settlement-import-bar { display: flex; flex-wrap: wrap; align-items: end; gap: .45rem .75rem; margin-top: .45rem; padding: .5rem .9rem; border: 1px solid var(--settlement-border); border-radius: .75rem; background: #fff; }
|
||
.settlement-import-bar .settlement-field { flex: 0 1 18rem; }
|
||
.settlement-import-bar input[type="file"] { width: 100%; height: 1.9rem; padding: .25rem .5rem; border: 1px dashed var(--settlement-border); border-radius: .4rem; background: #fffdf8; color: var(--settlement-ink); font: inherit; }
|
||
.settlement-import-bar .settlement-table-hint { align-self: center; flex-basis: 100%; }
|
||
.settlement-import-meta { display: flex; flex-wrap: wrap; align-items: center; gap: .15rem .9rem; margin-left: auto; align-self: center; color: var(--settlement-muted); font-size: .7rem; }
|
||
.settlement-import-meta strong { color: var(--settlement-ink); }
|
||
|
||
.settlement-table-surface { overflow: visible; border: 1px solid var(--settlement-border); border-radius: .75rem; background: #fff; }
|
||
.settlement-table-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .4rem .9rem; padding: .5rem .9rem; border-bottom: 1px solid var(--settlement-border); }
|
||
.settlement-table-head .finance-table-controls { margin: 0; padding: 0; border: 0; background: transparent; }
|
||
.settlement-table-title { display: flex; align-items: center; gap: .45rem; font-size: .9rem; font-weight: 700; }
|
||
.settlement-table-title .material-icons-outlined { color: var(--settlement-accent); font-size: 1.1rem; }
|
||
.settlement-table-hint { color: var(--settlement-muted); font-size: .68rem; }
|
||
.settlement-table-scroll { overflow: auto; overscroll-behavior: contain; scrollbar-gutter: stable both-edges; }
|
||
.surcharge-settlement-page .settlement-table-scroll { max-height: max(14rem, min(calc(100vh - 12rem), 46rem)); }
|
||
.settlement-table { width: max-content; min-width: 100%; border-collapse: separate; border-spacing: 0; font-size: .75rem; }
|
||
.settlement-table th,
|
||
.settlement-table td { min-width: 7.5rem; padding: .62rem .7rem; border-right: 1px solid var(--settlement-border); border-bottom: 1px solid var(--settlement-border); text-align: left; vertical-align: top; white-space: nowrap; }
|
||
.settlement-table th { background: var(--settlement-soft); font-weight: 700; }
|
||
.settlement-table th[data-finance-fixed="true"],
|
||
.settlement-table td[data-finance-fixed="true"] { background: #fffdf8; }
|
||
.settlement-table th[data-finance-fixed="end"],
|
||
.settlement-table td[data-finance-fixed="end"] { background: #fffdf8; }
|
||
.settlement-table td { overflow: hidden; text-overflow: ellipsis; }
|
||
.settlement-table .settlement-empty td { min-width: 22rem; padding: 3rem 1rem; text-align: center; color: var(--settlement-muted); white-space: normal; }
|
||
.settlement-table tbody tr.is-clickable { cursor: pointer; }
|
||
.settlement-table tbody tr.is-clickable:not(.is-active):hover td,
|
||
.settlement-table tbody tr.is-clickable:not(.is-active):hover td[data-finance-fixed="true"],
|
||
.settlement-table tbody tr.is-clickable:not(.is-active):hover td[data-finance-fixed="end"] { background: #fcfaf5; }
|
||
.settlement-table tbody tr.is-active td,
|
||
.settlement-table tbody tr.is-active td[data-finance-fixed="true"],
|
||
.settlement-table tbody tr.is-active td[data-finance-fixed="end"] { background: var(--settlement-soft); border-bottom-color: #e4d7ba; }
|
||
.settlement-table tbody tr.is-active td:first-child { box-shadow: inset 3px 0 0 var(--settlement-accent); }
|
||
.settlement-footer { display: flex; align-items: center; justify-content: space-between; gap: .6rem; padding: .35rem .15rem 0; color: var(--settlement-muted); font-size: .72rem; }
|
||
.settlement-pagination { display: flex; align-items: center; gap: .35rem; }
|
||
.settlement-page-link { display: inline-flex; align-items: center; justify-content: center; min-width: 1.7rem; height: 1.6rem; border: 1px solid var(--settlement-border); border-radius: .4rem; background: #fff; color: var(--settlement-ink); text-decoration: none; }
|
||
.settlement-page-link:hover { border-color: var(--settlement-accent); background: var(--settlement-soft); }
|
||
.settlement-page-link.is-disabled { opacity: .4; pointer-events: none; }
|
||
.settlement-page-link .material-icons-outlined { font-size: 1rem; }
|
||
.settlement-filter-picker .finance-table-field-picker__panel { right: auto; left: 0; max-width: min(28rem, calc(100vw - 1rem)); }
|
||
|
||
@media (max-width: 900px) {
|
||
.settlement-summary { grid-template-columns: 1fr 1fr; }
|
||
.settlement-summary__intro { grid-column: 1 / -1; }
|
||
.settlement-summary__metric:nth-child(2) { border-left: 0; }
|
||
.settlement-filter-bar { grid-template-columns: repeat(2, minmax(10rem, 1fr)); }
|
||
}
|
||
|
||
@media (max-width: 560px) {
|
||
.settlement-summary { grid-template-columns: 1fr; }
|
||
.settlement-summary__metric { border-left: 0; border-top: 1px solid var(--settlement-border); }
|
||
.settlement-filter-bar { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|
||
|
||
@if (session('error'))
|
||
<div class="settlement-notice" role="status">
|
||
<span class="material-icons-outlined" aria-hidden="true">error_outline</span>
|
||
<div><strong>导入核验失败</strong><div>{{ session('error') }}</div></div>
|
||
</div>
|
||
@endif
|
||
|
||
@if ($error !== null || ($sync['code'] ?? null) !== 'fresh')
|
||
<div class="settlement-notice" role="status">
|
||
<span class="material-icons-outlined" aria-hidden="true">{{ $error !== null ? 'error_outline' : 'info' }}</span>
|
||
<div>
|
||
<strong>{{ $error !== null ? '附加费结算暂不可用' : '附加费结算数据状态' }}</strong>
|
||
<div>{{ $error ?? $emptyMessage }}</div>
|
||
@if (! empty($state['failure_stage']))
|
||
<small>失败阶段:{{ $state['failure_stage'] }}</small>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
<div class="settlement-summary" aria-label="附加费结算概览">
|
||
<div class="settlement-summary__intro"><span class="settlement-summary__icon material-icons-outlined" aria-hidden="true">calculate</span><div><div class="settlement-summary__title">附加费结算</div><div class="settlement-summary__subtitle">结算标准读取附加费报价维护</div></div></div>
|
||
<div class="settlement-summary__metric"><div class="settlement-summary__label">筛选结果</div><div class="settlement-summary__value">{{ number_format((int) ($summary['count'] ?? $rows->total()), 0) }}</div></div>
|
||
<div class="settlement-summary__metric"><div class="settlement-summary__label">当前页结算金额</div><div class="settlement-summary__value">{{ number_format((float) ($summary['settlement_amount'] ?? 0), 2) }}</div></div>
|
||
<div class="settlement-summary__metric"><div class="settlement-summary__label">镜像状态</div><div class="settlement-summary__value">{{ $syncLabel }}</div></div>
|
||
</div>
|
||
|
||
<form class="settlement-filter-bar" method="GET" action="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-surcharge', 'tab' => 'settlement']) }}" aria-label="附加费结算筛选">
|
||
<div class="settlement-field" data-settlement-filter-field="courier_name"><label for="settlement-courier">快递名称</label><input id="settlement-courier" type="search" name="courier_name" value="{{ $filterValue('courier_name') }}" placeholder="输入快递名称"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="waybill"><label for="settlement-waybill">单号</label><input id="settlement-waybill" type="search" name="waybill" value="{{ $filterValue('waybill') }}" placeholder="输入单号"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="platform_product_id"><label for="settlement-platform-product">平台商品ID</label><input id="settlement-platform-product" type="search" name="platform_product_id" value="{{ $filterValue('platform_product_id') }}" placeholder="输入平台商品ID"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="product_code"><label for="settlement-product-code">商品编码</label><input id="settlement-product-code" type="search" name="product_code" value="{{ $filterValue('product_code') }}" placeholder="输入商品编码"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="shop_name"><label for="settlement-shop">店铺名称</label><input id="settlement-shop" type="search" name="shop_name" value="{{ $filterValue('shop_name') }}" placeholder="输入店铺名称"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="online_order_no"><label for="settlement-online-order">线上订单号</label><input id="settlement-online-order" type="search" name="online_order_no" value="{{ $filterValue('online_order_no') }}" placeholder="输入线上订单号"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="inspection_type"><label for="settlement-inspection">查件类型</label><input id="settlement-inspection" type="search" name="inspection_type" value="{{ $filterValue('inspection_type') }}" placeholder="一级选项"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="inspection_reason"><label for="settlement-reason">查件原因</label><input id="settlement-reason" type="search" name="inspection_reason" value="{{ $filterValue('inspection_reason') }}" placeholder="二级选项"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="surcharge_type"><label for="settlement-surcharge-type">附加费类型</label><select id="settlement-surcharge-type" name="surcharge_type"><option value="">全部附加费类型</option>@foreach (['退回费','拦截费','改地址','上楼费','送货费','超区费','安装费','保费','进仓费','超长费'] as $type)<option value="{{ $type }}" @selected($filterValue('surcharge_type') === $type)>{{ $type }}</option>@endforeach</select></div>
|
||
<div class="settlement-field" data-settlement-filter-field="status"><label for="settlement-status">结算状态</label><select id="settlement-status" name="status"><option value="">全部状态</option>@foreach (['未匹配报价','待核价','已计算'] as $status)<option value="{{ $status }}" @selected($filterValue('status') === $status)>{{ $status }}</option>@endforeach</select></div>
|
||
<div class="settlement-field" data-settlement-filter-field="created_from"><label for="settlement-created-from">创建日期起</label><input id="settlement-created-from" type="date" name="created_from" value="{{ $filterValue('created_from') }}"></div>
|
||
<div class="settlement-field" data-settlement-filter-field="created_to"><label for="settlement-created-to">创建日期止</label><input id="settlement-created-to" type="date" name="created_to" value="{{ $filterValue('created_to') }}"></div>
|
||
<div class="settlement-actions"><button class="settlement-button settlement-button--primary" type="submit"><span class="material-icons-outlined" aria-hidden="true">search</span>查询</button><a class="settlement-button" href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-surcharge', 'tab' => 'settlement']) }}"><span class="material-icons-outlined" aria-hidden="true">refresh</span>重置</a><a class="settlement-button" href="{{ route('business.courier-surcharge.settlement.export', array_filter($filters, static fn ($value): bool => $value !== '' && $value !== null)) }}" title="按当前筛选导出附加费结算明细(XLSX,仅含已生成结算行的数据;未生成结算行的运单请用导入核验)"><span class="material-icons-outlined" aria-hidden="true">download</span>导出</a><div class="finance-table-field-picker settlement-filter-picker" data-settlement-filter-picker data-user="{{ auth()->id() }}"><button type="button" class="settlement-button" aria-expanded="false" title="选择要显示的筛选字段,选择会自动保存"><span class="material-icons-outlined" aria-hidden="true">tune</span>筛选设置</button><div class="finance-table-field-picker__panel" role="group" aria-label="选择筛选字段" hidden>@foreach (['courier_name' => '快递名称', 'waybill' => '单号', 'platform_product_id' => '平台商品ID', 'product_code' => '商品编码', 'shop_name' => '店铺名称', 'online_order_no' => '线上订单号', 'inspection_type' => '查件类型', 'inspection_reason' => '查件原因', 'surcharge_type' => '附加费类型', 'status' => '结算状态', 'created_from' => '创建日期起', 'created_to' => '创建日期止'] as $fieldKey => $fieldLabel)<label class="finance-table-field-picker__option"><input type="checkbox" value="{{ $fieldKey }}" data-settlement-filter-check checked><span>{{ $fieldLabel }}</span></label>@endforeach<div class="finance-table-field-picker__actions"><button type="button" data-settlement-filters-all>全选</button><button type="button" data-settlement-filters-reset>恢复默认</button></div></div></div></div>
|
||
</form>
|
||
|
||
<form class="settlement-import-bar" method="POST" action="{{ route('business.courier-surcharge.settlement.import') }}" enctype="multipart/form-data" aria-label="附加费结算导入核验">
|
||
@csrf
|
||
<div class="settlement-field">
|
||
<label for="settlement-import-file">导入核验(单号 + 附加费类型)</label>
|
||
<input id="settlement-import-file" type="file" name="file" accept=".xlsx,.xls,.csv" required>
|
||
</div>
|
||
<div class="settlement-actions">
|
||
<button class="settlement-button settlement-button--primary" type="submit"><span class="material-icons-outlined" aria-hidden="true">upload_file</span>导入并下载结果</button>
|
||
<a class="settlement-button" href="{{ route('business.courier-surcharge.settlement.import-template') }}"><span class="material-icons-outlined" aria-hidden="true">download</span>下载导入模板</a>
|
||
</div>
|
||
<div class="settlement-import-meta" role="status"><span>当前筛选结果:<strong>{{ number_format((int) ($summary['count'] ?? $rows->total()), 0) }}</strong> 条</span><span>数据状态:{{ $syncLabel }}@if (! empty($sync['last_succeeded_at'])),最近同步 {{ $sync['last_succeeded_at'] }}@endif</span></div>
|
||
<span class="settlement-table-hint">首行只需「单号」「附加费类型」:系统会按单号自动匹配快递,并按启用的报价核算应结金额;「金额」可选,填了会返回与系统的差异金额。</span>
|
||
</form>
|
||
|
||
<div class="settlement-table-surface" data-finance-table-surface>
|
||
<div class="settlement-table-head"><div><div class="settlement-table-title"><span class="material-icons-outlined" aria-hidden="true">table_view</span>附加费结算明细</div><div class="settlement-table-hint">快递名称和附加费类型固定显示,其余字段可在“列设置”中调整;点击行可高亮标记。</div></div><div class="finance-table-controls" data-finance-controls></div></div>
|
||
<div class="settlement-table-scroll finance-table-scroll-owner">
|
||
<table class="settlement-table" data-finance-table data-finance-table-name="courier-surcharge-settlement" data-finance-table-key="{{ auth()->id() }}:{{ company_id() }}:courier-payables:courier-surcharge:settlement:details" aria-label="附加费结算明细">
|
||
<thead><tr>
|
||
@foreach ($columns as $column)
|
||
<th scope="col" data-finance-column-key="{{ $column['key'] }}" data-finance-fixed="{{ $column['fixed'] ?? '' }}" data-export-field="{{ $column['key'] }}">{{ $column['label'] }}</th>
|
||
@endforeach
|
||
</tr></thead>
|
||
<tbody>
|
||
@forelse ($rows as $row)
|
||
<tr class="is-clickable" data-settlement-row>
|
||
@foreach ($columns as $column)
|
||
<td data-finance-column-key="{{ $column['key'] }}" data-export-value="{{ $displayValue(data_get($row, $column['key']), $column['key']) }}">{{ $displayValue(data_get($row, $column['key']), $column['key']) }}</td>
|
||
@endforeach
|
||
</tr>
|
||
@empty
|
||
<tr class="settlement-empty is-empty"><td colspan="{{ count($columns) }}"><span class="material-icons-outlined" aria-hidden="true">{{ $error !== null ? 'error_outline' : 'inbox' }}</span><div>{{ $emptyMessage }}</div></td></tr>
|
||
@endforelse
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
@if (method_exists($rows, 'hasPages') && $rows->hasPages())
|
||
<div class="settlement-footer">
|
||
<span>第 {{ $rows->currentPage() }} / {{ $rows->lastPage() }} 页,本页 {{ $rows->count() }} 条,共 {{ number_format($rows->total()) }} 条</span>
|
||
<div class="settlement-pagination">
|
||
<a class="settlement-page-link {{ $rows->onFirstPage() ? 'is-disabled' : '' }}" href="{{ $rows->onFirstPage() ? '#' : $rows->url($rows->currentPage() - 1) }}" aria-label="上一页">
|
||
<span class="material-icons-outlined" aria-hidden="true">chevron_left</span>
|
||
</a>
|
||
<a class="settlement-page-link {{ $rows->hasMorePages() ? '' : 'is-disabled' }}" href="{{ $rows->hasMorePages() ? $rows->url($rows->currentPage() + 1) : '#' }}" aria-label="下一页">
|
||
<span class="material-icons-outlined" aria-hidden="true">chevron_right</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
</section>
|
||
|
||
<script>
|
||
(() => {
|
||
const table = document.querySelector('table[data-finance-table-name="courier-surcharge-settlement"]');
|
||
|
||
if (!table) {
|
||
return;
|
||
}
|
||
|
||
const activate = (row) => {
|
||
table.querySelectorAll('tbody tr.is-active').forEach((item) => item.classList.remove('is-active'));
|
||
row.classList.add('is-active');
|
||
};
|
||
|
||
document.addEventListener('click', (event) => {
|
||
if (!(event.target instanceof Element) || event.target.closest('a, button, input, label, select')) {
|
||
return;
|
||
}
|
||
|
||
const row = event.target.closest('tr[data-settlement-row]');
|
||
|
||
if (row && table.contains(row)) {
|
||
event.preventDefault();
|
||
activate(row);
|
||
}
|
||
});
|
||
|
||
})();
|
||
|
||
(() => {
|
||
const filterBar = document.querySelector('.settlement-filter-bar');
|
||
const filterPicker = document.querySelector('[data-settlement-filter-picker]');
|
||
|
||
if (filterBar && filterPicker) {
|
||
const toggle = filterPicker.querySelector('button[aria-expanded]');
|
||
const panel = filterPicker.querySelector('.finance-table-field-picker__panel');
|
||
const checks = [...panel.querySelectorAll('input[data-settlement-filter-check]')];
|
||
const fields = [...filterBar.querySelectorAll('[data-settlement-filter-field]')];
|
||
const storageKey = 'caiwu:courier-surcharge-settlement:filter-fields:' + (filterPicker.dataset.user || 'anonymous');
|
||
const defaultKeys = checks.map((check) => check.value);
|
||
|
||
const apply = (selected, save) => {
|
||
fields.forEach((field) => {
|
||
const visible = selected.has(field.dataset.settlementFilterField);
|
||
field.hidden = !visible;
|
||
field.querySelectorAll('input, select').forEach((control) => {
|
||
if (visible) {
|
||
control.removeAttribute('disabled');
|
||
} else {
|
||
control.setAttribute('disabled', 'disabled');
|
||
}
|
||
});
|
||
});
|
||
checks.forEach((check) => { check.checked = selected.has(check.value); });
|
||
if (save) {
|
||
try { localStorage.setItem(storageKey, JSON.stringify([...selected])); } catch (_) {}
|
||
}
|
||
};
|
||
|
||
let stored = null;
|
||
try {
|
||
const parsed = JSON.parse(localStorage.getItem(storageKey) ?? 'null');
|
||
if (Array.isArray(parsed)) {
|
||
stored = new Set(parsed.filter((key) => defaultKeys.includes(key)));
|
||
}
|
||
} catch (_) {}
|
||
|
||
apply(stored ?? new Set(defaultKeys), false);
|
||
|
||
toggle.addEventListener('click', () => {
|
||
const open = panel.hidden;
|
||
panel.hidden = !open;
|
||
toggle.setAttribute('aria-expanded', String(open));
|
||
});
|
||
|
||
document.addEventListener('click', (event) => {
|
||
if (!panel.hidden && !filterPicker.contains(event.target)) {
|
||
panel.hidden = true;
|
||
toggle.setAttribute('aria-expanded', 'false');
|
||
}
|
||
});
|
||
|
||
checks.forEach((check) => check.addEventListener('change', () => {
|
||
apply(new Set(checks.filter((item) => item.checked).map((item) => item.value)), true);
|
||
}));
|
||
|
||
panel.querySelector('[data-settlement-filters-all]')?.addEventListener('click', () => {
|
||
apply(new Set(defaultKeys), true);
|
||
});
|
||
|
||
panel.querySelector('[data-settlement-filters-reset]')?.addEventListener('click', () => {
|
||
try { localStorage.removeItem(storageKey); } catch (_) {}
|
||
apply(new Set(defaultKeys), true);
|
||
});
|
||
}
|
||
})();
|
||
</script>
|