合并:新增原材料库存明细页面

This commit is contained in:
WuYongJie 2026-07-22 13:41:26 +08:00
parent 2c0aaab550
commit b008ff602a
2 changed files with 336 additions and 0 deletions

View File

@ -0,0 +1,28 @@
@include('business.pages.partials.data-table', [
'title' => $page['title'] ?? '板材库存明细',
'showIndex' => false,
'filters' => [
['name' => 'manufacturer', 'label' => '厂家', 'placeholder' => '输入厂家'],
['name' => 'date_from', 'label' => '日期从', 'type' => 'date'],
['name' => 'date_to', 'label' => '日期至', 'type' => 'date'],
['name' => 'specification', 'label' => '规格', 'placeholder' => '输入规格'],
['name' => 'matching_value', 'label' => '匹配用', 'placeholder' => '输入匹配条件'],
],
'columns' => [
['key' => 'manufacturer', 'label' => '厂家'],
['key' => 'date', 'label' => '日期'],
['key' => 'specification', 'label' => '规格'],
['key' => 'matching_value', 'label' => '匹配用'],
['key' => 'opening_balance', 'label' => '上月结余'],
['key' => 'weighted_average_price', 'label' => '加权平均单价'],
['key' => 'stock_in', 'label' => '入库'],
['key' => 'lamination_out', 'label' => '压贴'],
['key' => 'inventory', 'label' => '库存'],
['key' => 'remaining_value', 'label' => '剩余价值'],
['key' => 'stock_in_amount', 'label' => '入库金额'],
['key' => 'closing_remaining_value', 'label' => '剩余价值'],
['key' => 'previous_remaining_value', 'label' => '上月剩余价值'],
['key' => 'stock_out_amount', 'label' => '出库金额'],
],
'emptyText' => '暂无板材库存明细数据',
])

View File

@ -0,0 +1,308 @@
@php
$records = $records ?? [];
$filters = $filters ?? [];
$columns = $columns ?? [];
$showIndex = $showIndex ?? true;
$recordCount = is_countable($records) ? count($records) : 0;
@endphp
<style>
#main-body > .container {
width: auto;
max-width: none;
margin-right: 1.5rem;
margin-left: 1.5rem;
}
.business-data-page {
--table-border: #e5e7eb;
--table-muted: #6b7280;
--table-ink: #1f2937;
--table-accent: #2563eb;
margin: 1.5rem 0;
}
.business-data-page .page-heading {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 1rem;
margin-bottom: 1.25rem;
}
.business-data-page .page-heading h1 {
margin: 0;
color: var(--table-ink);
font-size: 1.25rem;
font-weight: 700;
letter-spacing: 0;
}
.business-data-page .filter-panel,
.business-data-page .table-panel {
border: 1px solid var(--table-border);
border-radius: 0.5rem;
background: #ffffff;
box-shadow: 0 4px 14px rgba(31, 41, 55, 0.04);
}
.business-data-page .filter-panel {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 0.75rem 1rem;
padding: 1rem 1.125rem;
}
.business-data-page .filter-field {
display: flex;
min-width: 10rem;
flex: 0 1 13rem;
flex-direction: column;
gap: 0.3rem;
}
.business-data-page .filter-field label {
color: var(--table-muted);
font-size: 0.75rem;
letter-spacing: 0;
}
.business-data-page .filter-field input,
.business-data-page .filter-field select {
min-height: 2.25rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
background: #ffffff;
padding: 0.35rem 0.65rem;
color: var(--table-ink);
font-size: 0.8125rem;
letter-spacing: 0;
outline: none;
}
.business-data-page .filter-field input:focus,
.business-data-page .filter-field select:focus {
border-color: var(--table-accent);
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.12);
}
.business-data-page .filter-actions {
display: flex;
align-items: center;
gap: 0.5rem;
}
.business-data-page .filter-actions button,
.business-data-page .filter-actions a {
display: inline-flex;
min-height: 2.25rem;
align-items: center;
gap: 0.35rem;
border-radius: 0.375rem;
padding: 0.35rem 0.75rem;
font-size: 0.8125rem;
letter-spacing: 0;
transition: background-color 150ms ease, border-color 150ms ease;
}
.business-data-page .filter-actions button {
border: 1px solid var(--table-accent);
background: var(--table-accent);
color: #ffffff;
}
.business-data-page .filter-actions button:hover {
background: #1d4ed8;
}
.business-data-page .filter-actions a {
border: 1px solid #d1d5db;
color: #4b5563;
}
.business-data-page .filter-actions a:hover {
border-color: #9ca3af;
background: #f9fafb;
}
.business-data-page .table-panel {
margin-top: 1.25rem;
overflow: hidden;
}
.business-data-page .table-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
border-bottom: 1px solid var(--table-border);
padding: 0.8rem 1rem;
}
.business-data-page .table-toolbar strong {
color: var(--table-ink);
font-size: 0.875rem;
}
.business-data-page .table-toolbar span {
color: var(--table-muted);
font-size: 0.75rem;
}
.business-data-page .table-scroll {
overflow-x: auto;
}
.business-data-page table {
width: max-content;
min-width: 100%;
border-collapse: collapse;
color: var(--table-ink);
font-size: 0.75rem;
letter-spacing: 0;
white-space: nowrap;
}
.business-data-page th,
.business-data-page td {
min-width: 7rem;
border-right: 1px solid #eef0f3;
border-bottom: 1px solid #eef0f3;
padding: 0.65rem 0.75rem;
text-align: left;
}
.business-data-page th:last-child,
.business-data-page td:last-child {
border-right: 0;
}
.business-data-page thead th {
background: #f9fafb;
color: #4b5563;
font-weight: 600;
text-align: center;
}
.business-data-page tbody tr:hover {
background: #eff6ff;
}
.business-data-page .index-column {
position: sticky;
left: 0;
z-index: 1;
min-width: 3.5rem;
background: #ffffff;
text-align: center;
}
.business-data-page thead .index-column {
background: #f9fafb;
}
.business-data-page tbody tr:hover .index-column {
background: #eff6ff;
}
.business-data-page .empty-row td {
padding: 4rem 1rem;
color: #9ca3af;
text-align: center;
}
@media (max-width: 768px) {
#main-body > .container {
margin-right: 0.75rem;
margin-left: 0.75rem;
}
.business-data-page .filter-field {
min-width: min(100%, 13rem);
flex: 1 1 13rem;
}
}
</style>
<div class="business-data-page">
<div class="page-heading">
<h1>{{ $title }}</h1>
</div>
<form method="GET" class="filter-panel" aria-label="{{ $title }}筛选">
@foreach ($filters as $filter)
<div class="filter-field">
<label for="business-filter-{{ $filter['name'] }}">{{ $filter['label'] }}</label>
@if (($filter['type'] ?? 'text') === 'select')
<select id="business-filter-{{ $filter['name'] }}" name="{{ $filter['name'] }}">
@foreach ($filter['options'] ?? [] as $value => $label)
<option value="{{ $value }}" @selected((string) request($filter['name']) === (string) $value)>{{ $label }}</option>
@endforeach
</select>
@else
<input
id="business-filter-{{ $filter['name'] }}"
type="{{ $filter['type'] ?? 'text' }}"
name="{{ $filter['name'] }}"
value="{{ request($filter['name']) }}"
placeholder="{{ $filter['placeholder'] ?? '' }}"
>
@endif
</div>
@endforeach
<div class="filter-actions">
<button type="submit">
<span class="material-icons-outlined text-base" aria-hidden="true">search</span>
<span>查询</span>
</button>
<a href="{{ url()->current() }}" aria-label="重置筛选" title="重置筛选">
<span class="material-icons-outlined text-base" aria-hidden="true">restart_alt</span>
<span>重置</span>
</a>
</div>
</form>
<div class="table-panel">
<div class="table-toolbar">
<strong>{{ $title }}</strong>
<span>共 {{ $recordCount }} 条</span>
</div>
<div class="table-scroll">
<table>
<thead>
<tr>
@if ($showIndex)
<th class="index-column">序号</th>
@endif
@foreach ($columns as $column)
<th>{{ $column['label'] }}</th>
@endforeach
</tr>
</thead>
<tbody>
@forelse ($records as $index => $record)
<tr>
@if ($showIndex)
<td class="index-column">{{ $index + 1 }}</td>
@endif
@foreach ($columns as $column)
@php($value = data_get($record, $column['key']))
<td>{{ $value === null || $value === '' ? '-' : $value }}</td>
@endforeach
</tr>
@empty
<tr class="empty-row">
<td colspan="{{ count($columns) + ($showIndex ? 1 : 0) }}">
<span class="material-icons-outlined block mb-2 text-3xl" aria-hidden="true">table_rows</span>
{{ $emptyText ?? '暂无数据' }}
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>