合并:新增素板、快递及商品价格页面

This commit is contained in:
WuYongJie 2026-07-22 13:40:25 +08:00
parent fa9444bbbe
commit 2c0aaab550
12 changed files with 1334 additions and 2 deletions

View File

@ -183,8 +183,8 @@ return [
'title' => '原材料-素板应付',
'icon' => 'view_module',
'pages' => [
['slug' => 'board-prices', 'title' => '素版价格'],
['slug' => 'board-reconciliation', 'title' => '素版对账'],
['slug' => 'board-prices', 'title' => '素板价格'],
['slug' => 'board-reconciliation', 'title' => '素板对账'],
['slug' => 'compensation-details', 'title' => '赔付明细'],
['slug' => 'board-payables-report', 'title' => '素板应付表'],
],

View File

@ -0,0 +1,29 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '借支明细',
'filters' => [
['name' => 'carrier', 'label' => '快递名称', 'placeholder' => '输入快递名称'],
['name' => 'agreement_name', 'label' => '协议签订名称', 'placeholder' => '输入协议名称'],
['name' => 'payment_status', 'label' => '是否打款', 'type' => 'select', 'options' => ['' => '全部']],
['name' => 'advance_from', 'label' => '借支日期从', 'type' => 'date'],
['name' => 'advance_to', 'label' => '借支日期至', 'type' => 'date'],
],
'columns' => [
['key' => 'carrier', 'label' => '快递名称'],
['key' => 'agreement_name', 'label' => '协议签订名称'],
['key' => 'agreement_amount', 'label' => '借支金额-借款协议'],
['key' => 'actual_paid_amount', 'label' => '实际打款金额'],
['key' => 'monthly_deduction', 'label' => '本月扣款金额'],
['key' => 'deduction_start_month', 'label' => '分期起始扣款月份'],
['key' => 'deduction_end_month', 'label' => '分期最后次扣款月份'],
['key' => 'remaining_periods', 'label' => '分期剩余期数'],
['key' => 'advanced_at', 'label' => '借支日期'],
['key' => 'loan_term', 'label' => '借款期限'],
['key' => 'remark', 'label' => '备注'],
['key' => 'payment_status', 'label' => '是否打款'],
['key' => 'payment_month', 'label' => '打款月份'],
['key' => 'serial_no', 'label' => '流水号'],
['key' => 'agreement_file', 'label' => '借支协议'],
['key' => 'reviewer', 'label' => '审核人'],
],
'emptyText' => '暂无借支明细',
])

View File

@ -0,0 +1,63 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '记账明细',
'filters' => [
['name' => 'keyword', 'label' => '工单/订单号', 'placeholder' => '输入编号'],
['name' => 'bookkeeping_type', 'label' => '记账类型', 'type' => 'select', 'options' => ['' => '全部']],
['name' => 'status', 'label' => '处理状态', 'type' => 'select', 'options' => ['' => '全部']],
['name' => 'started_from', 'label' => '发起时间从', 'type' => 'date'],
['name' => 'started_to', 'label' => '发起时间至', 'type' => 'date'],
],
'groups' => [
['label' => '记账信息', 'span' => 13],
['label' => '订单与处理', 'span' => 16],
['label' => '商品信息', 'span' => 12],
['label' => '工单补充', 'span' => 3],
],
'columns' => [
['key' => 'started_at', 'label' => '发起时间'],
['key' => 'work_order_no', 'label' => '工单编号'],
['key' => 'initiator', 'label' => '发起人'],
['key' => 'bookkeeping_reason', 'label' => '记账原因'],
['key' => 'reason_level_1', 'label' => '记账原因-一级选项'],
['key' => 'reason_level_2', 'label' => '记账原因-二级选项'],
['key' => 'reason_level_3', 'label' => '记账原因-三级选项'],
['key' => 'bookkeeping_type', 'label' => '记账类型'],
['key' => 'executor', 'label' => '执行人'],
['key' => 'source', 'label' => '记账来源'],
['key' => 'amount', 'label' => '记账金额'],
['key' => 'remark', 'label' => '记账备注说明'],
['key' => 'attachment', 'label' => '上传附件'],
['key' => 'attachment_preview', 'label' => '上传附件(预览)'],
['key' => 'online_order_no', 'label' => '线上订单号'],
['key' => 'internal_order_no', 'label' => '内部单号'],
['key' => 'actual_paid_amount', 'label' => '实付金额'],
['key' => 'carrier', 'label' => '物流公司'],
['key' => 'tracking_no', 'label' => '物流单号'],
['key' => 'shop_name', 'label' => '店铺名称'],
['key' => 'platform', 'label' => '平台'],
['key' => 'shipping_warehouse', 'label' => '订单发货仓库'],
['key' => 'processing_status', 'label' => '记账处理状态'],
['key' => 'counterparty_agreed', 'label' => '被记账方是否同意记账'],
['key' => 'counterparty_note', 'label' => '被记账方处理说明'],
['key' => 'specialist_result', 'label' => '专员记账判定结果'],
['key' => 'specialist_note', 'label' => '专员处理说明'],
['key' => 'updated_at', 'label' => '修改时间'],
['key' => 'work_order_type', 'label' => '工单类型'],
['key' => 'product_image', 'label' => '商品图片'],
['key' => 'product_code', 'label' => '商品编码'],
['key' => 'style_code', 'label' => '款式编码'],
['key' => 'other_attribute_6', 'label' => '其它属性6'],
['key' => 'product_name', 'label' => '商品名称'],
['key' => 'platform_sku_id', 'label' => '平台商品skuid'],
['key' => 'platform_product_id', 'label' => '平台商品id'],
['key' => 'product_quantity', 'label' => '商品数量'],
['key' => 'product_price', 'label' => '商品价格'],
['key' => 'product_amount', 'label' => '商品金额'],
['key' => 'buyer_paid_amount', 'label' => '买家实付'],
['key' => 'supplier', 'label' => '供应商'],
['key' => 'accepting_department', 'label' => '受理部门'],
['key' => 'order_shipped_at', 'label' => '订单发货时间'],
['key' => 'work_order_remark', 'label' => '工单备注'],
],
'emptyText' => '暂无记账明细',
])

View File

@ -0,0 +1,18 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '赔偿明细',
'filters' => [
['name' => 'carrier', 'label' => '承运商', 'placeholder' => '输入承运商'],
['name' => 'tracking_no', 'label' => '快递单号', 'placeholder' => '输入快递单号'],
['name' => 'paid_from', 'label' => '赔付日期从', 'type' => 'date'],
['name' => 'paid_to', 'label' => '赔付日期至', 'type' => 'date'],
],
'columns' => [
['key' => 'paid_at', 'label' => '赔付日期'],
['key' => 'carrier', 'label' => '承运商'],
['key' => 'tracking_no', 'label' => '快递单号'],
['key' => 'amount', 'label' => '赔付金额'],
['key' => 'reason', 'label' => '赔付原因'],
['key' => 'remark', 'label' => '备注'],
],
'emptyText' => '暂无赔偿明细',
])

View File

@ -0,0 +1,311 @@
<!--
快递应付 - 运费对账
表头设计来源: 快递应付-运费对账功能页面的表头.xls (45列)
-->
<style>
#main-body > .container {
max-width: none;
width: auto;
margin-left: 1.5rem;
margin-right: 1.5rem;
}
</style>
<div class="w-full">
<!-- Page Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<div>
<h1 class="text-xl font-semibold text-gray-800">{{ $page['title'] ?? '运费对账' }}</h1>
</div>
</div>
<!-- Filter Bar -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 mb-6">
<form method="GET" class="flex flex-wrap items-end gap-3">
<div class="flex flex-col min-w-[140px]">
<label class="text-xs text-gray-500 mb-1">快递单号</label>
<input type="text" name="express_no" value="{{ request('express_no') }}" placeholder="搜索快递单号"
class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-400 focus:border-blue-400 outline-none">
</div>
<div class="flex flex-col min-w-[120px]">
<label class="text-xs text-gray-500 mb-1">条形码</label>
<input type="text" name="barcode" value="{{ request('barcode') }}" placeholder="搜索条形码"
class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-400 focus:border-blue-400 outline-none">
</div>
<div class="flex flex-col min-w-[120px]">
<label class="text-xs text-gray-500 mb-1">快递名称</label>
<input type="text" name="express_name" value="{{ request('express_name') }}" placeholder="快递公司"
class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-400 focus:border-blue-400 outline-none">
</div>
<div class="flex flex-col min-w-[120px]">
<label class="text-xs text-gray-500 mb-1">平台</label>
<select name="platform"
class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-400 focus:border-blue-400 outline-none bg-white">
<option value="">全部</option>
<option value="淘宝天猫" {{ request('platform') === '淘宝天猫' ? 'selected' : '' }}>淘宝天猫</option>
<option value="京东商城" {{ request('platform') === '京东商城' ? 'selected' : '' }}>京东商城</option>
<option value="拼多多" {{ request('platform') === '拼多多' ? 'selected' : '' }}>拼多多</option>
</select>
</div>
<div class="flex flex-col min-w-[110px]">
<label class="text-xs text-gray-500 mb-1">供应商</label>
<input type="text" name="supplier" value="{{ request('supplier') }}" placeholder="供应商"
class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-400 focus:border-blue-400 outline-none">
</div>
<div class="flex flex-col min-w-[130px]">
<label class="text-xs text-gray-500 mb-1">发货时间 从</label>
<input type="date" name="ship_from" value="{{ request('ship_from') }}"
class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-400 focus:border-blue-400 outline-none">
</div>
<div class="flex flex-col min-w-[130px]">
<label class="text-xs text-gray-500 mb-1">发货时间 至</label>
<input type="date" name="ship_to" value="{{ request('ship_to') }}"
class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-400 focus:border-blue-400 outline-none">
</div>
<div class="flex gap-2">
<button type="submit"
class="bg-blue-500 hover:bg-blue-600 text-white text-sm px-4 py-1.5 rounded transition">
查询
</button>
<a href="{{ url()->current() }}"
class="border border-gray-300 text-gray-600 text-sm px-4 py-1.5 rounded hover:bg-gray-50 transition">
重置
</a>
</div>
</form>
</div>
<!-- Data Table - 45 columns with horizontal scroll -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-xs whitespace-nowrap">
<thead>
<!-- Column Group Headers -->
<tr class="bg-gray-100 border-b border-gray-300 text-gray-500 font-medium">
<th class="sticky left-0 bg-gray-100 z-10 px-2 py-1.5 text-center border-r border-gray-200" style="min-width:40px">#</th>
<!-- 物流信息 (10 cols) -->
<th class="px-2 py-1 text-center border-r border-gray-200" colspan="10" style="min-width:800px">物流信息</th>
<!-- 订单信息 (8 cols) -->
<th class="px-2 py-1 text-center border-r border-gray-200" colspan="8" style="min-width:700px">订单信息</th>
<!-- 收件信息 (7 cols) -->
<th class="px-2 py-1 text-center border-r border-gray-200" colspan="7" style="min-width:650px">收件信息</th>
<!-- 商品规格 (5 cols) -->
<th class="px-2 py-1 text-center border-r border-gray-200" colspan="5" style="min-width:380px">商品规格</th>
<!-- 平台/店铺 (3 cols) -->
<th class="px-2 py-1 text-center border-r border-gray-200" colspan="3" style="min-width:300px">平台/店铺</th>
<!-- 供应商/仓库 (5 cols) -->
<th class="px-2 py-1 text-center border-r border-gray-200" colspan="5" style="min-width:480px">供应商/仓库</th>
<!-- 时间 (3 cols) -->
<th class="px-2 py-1 text-center border-r border-gray-200" colspan="3" style="min-width:400px">时间</th>
<!-- 备注 (2 cols) -->
<th class="px-2 py-1 text-center" colspan="2" style="min-width:220px">备注</th>
</tr>
<!-- Column Sub-Headers -->
<tr class="bg-gray-50 border-b border-gray-200 text-gray-600 font-medium">
<th class="sticky left-0 bg-gray-50 z-10 px-2 py-1.5 text-center border-r border-gray-200" style="min-width:40px">#</th>
{{-- 物流信息 --}}
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:140px">快递单号</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">快递名称1</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">快递名称2</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:70px">运费</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:80px">费率</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:70px">结算重量</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:80px">结算体积</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:70px">对账重量</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:80px">对账体积</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:120px">换单前单号</th>
{{-- 订单信息 --}}
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:140px">交易单号</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">商品ID</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:120px">条形码</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:160px">商品名称</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:50px">数量</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:70px">金额</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">货号</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">配货单号</th>
{{-- 收件信息 --}}
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:50px">省</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:70px">市</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:70px">区</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:200px">收货详细地址</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:70px">收货姓名</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">手机号码</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:90px">座机号码</th>
{{-- 商品规格 --}}
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:60px">长(cm)</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:60px">宽(cm)</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:60px">高(cm)</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:80px">体积(cm³)</th>
<th class="px-2 py-1.5 border-r border-gray-200 text-right" style="min-width:80px">重量(kg)</th>
{{-- 平台/店铺 --}}
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:90px">平台</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:130px">店铺名称</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">买家昵称</th>
{{-- 供应商/仓库 --}}
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:140px">供应商</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:120px">仓库</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:100px">成品条码</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:120px">成品名称</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:120px">成品供应商</th>
{{-- 时间 --}}
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:140px">发货时间</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:120px">下载时间</th>
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:120px">付款时间</th>
{{-- 备注 --}}
<th class="px-2 py-1.5 border-r border-gray-200" style="min-width:130px">买家留言</th>
<th class="px-2 py-1.5" style="min-width:130px">卖家备注</th>
</tr>
</thead>
<tbody>
@forelse ($freightReconciliations ?? [] as $index => $item)
<tr class="border-b border-gray-100 hover:bg-blue-50/40 transition">
<td class="sticky left-0 bg-white z-10 px-2 py-2 text-center text-gray-400 border-r border-gray-100">
{{ ($freightReconciliations->currentPage() - 1) * $freightReconciliations->perPage() + $index + 1 }}
</td>
{{-- 物流信息 --}}
<td class="px-2 py-2 mono text-blue-600 border-r border-gray-100">{{ $item['express_no'] ?? '-' }}</td>
<td class="px-2 py-2 border-r border-gray-100">{{ $item['express_name1'] ?? '-' }}</td>
<td class="px-2 py-2 border-r border-gray-100">{{ $item['express_name2'] ?? '-' }}</td>
<td class="px-2 py-2 text-right font-medium border-r border-gray-100 {{ ($item['freight'] ?? 0) > 0 ? 'text-gray-800' : 'text-gray-300' }}">
{{ isset($item['freight']) ? number_format((float) $item['freight'], 2) : '-' }}
</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ $item['rate'] ?? '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['settle_weight']) ? number_format((float) $item['settle_weight'], 4) : '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['settle_volume']) ? number_format((float) $item['settle_volume'], 4) : '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['recon_weight']) ? number_format((float) $item['recon_weight'], 4) : '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['recon_volume']) ? number_format((float) $item['recon_volume'], 4) : '-' }}</td>
<td class="px-2 py-2 text-gray-400 border-r border-gray-100 text-xs">{{ $item['prev_express_no'] ?? '-' }}</td>
{{-- 订单信息 --}}
<td class="px-2 py-2 mono text-xs text-gray-500 border-r border-gray-100">{{ $item['trade_no'] ?? '-' }}</td>
<td class="px-2 py-2 mono text-xs text-gray-500 border-r border-gray-100">{{ $item['product_id'] ?? '-' }}</td>
<td class="px-2 py-2 mono text-gray-700 border-r border-gray-100">{{ $item['barcode'] ?? '-' }}</td>
<td class="px-2 py-2 border-r border-gray-100 max-w-[160px] truncate" title="{{ $item['product_name'] ?? '' }}">
{{ $item['product_name'] ?? '-' }}
</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ $item['qty'] ?? '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['amount']) ? number_format((float) $item['amount'], 2) : '-' }}</td>
<td class="px-2 py-2 text-gray-400 text-xs border-r border-gray-100">{{ $item['item_no'] ?? '-' }}</td>
<td class="px-2 py-2 text-gray-400 text-xs border-r border-gray-100">{{ $item['pick_no'] ?? '-' }}</td>
{{-- 收件信息 --}}
<td class="px-2 py-2 border-r border-gray-100">{{ $item['province'] ?? '-' }}</td>
<td class="px-2 py-2 border-r border-gray-100">{{ $item['city'] ?? '-' }}</td>
<td class="px-2 py-2 border-r border-gray-100">{{ $item['district'] ?? '-' }}</td>
<td class="px-2 py-2 text-gray-400 text-xs border-r border-gray-100 max-w-[200px] truncate" title="{{ $item['address'] ?? '' }}">
{{ $item['address'] ?? '-' }}
</td>
<td class="px-2 py-2 border-r border-gray-100">{{ $item['receiver_name'] ?? '-' }}</td>
<td class="px-2 py-2 mono text-xs border-r border-gray-100">{{ $item['receiver_phone'] ?? '-' }}</td>
<td class="px-2 py-2 mono text-xs text-gray-400 border-r border-gray-100">{{ $item['receiver_tel'] ?? '-' }}</td>
{{-- 商品规格 --}}
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['length']) ? number_format((float) $item['length'], 2) : '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['width']) ? number_format((float) $item['width'], 2) : '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['height']) ? number_format((float) $item['height'], 2) : '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['volume']) ? number_format((float) $item['volume'], 4) : '-' }}</td>
<td class="px-2 py-2 text-right border-r border-gray-100">{{ isset($item['weight']) ? number_format((float) $item['weight'], 4) : '-' }}</td>
{{-- 平台/店铺 --}}
<td class="px-2 py-2 border-r border-gray-100">
<span class="platform-tag {{ str_contains($item['platform'] ?? '', '天猫') || str_contains($item['platform'] ?? '', '淘宝') ? 'bg-orange-100 text-orange-700' : (str_contains($item['platform'] ?? '', '京东') ? 'bg-red-100 text-red-700' : (str_contains($item['platform'] ?? '', '拼多多') ? 'bg-pink-100 text-pink-700' : 'bg-gray-100 text-gray-600')) }} text-xs px-1.5 py-0.5 rounded">
{{ $item['platform'] ?? '-' }}
</span>
</td>
<td class="px-2 py-2 text-xs text-gray-500 border-r border-gray-100 max-w-[130px] truncate" title="{{ $item['shop_name'] ?? '' }}">
{{ $item['shop_name'] ?? '-' }}
</td>
<td class="px-2 py-2 text-gray-400 text-xs border-r border-gray-100">{{ $item['buyer_nick'] ?? '-' }}</td>
{{-- 供应商/仓库 --}}
<td class="px-2 py-2 border-r border-gray-100">{{ $item['supplier'] ?? '-' }}</td>
<td class="px-2 py-2 text-xs text-gray-500 border-r border-gray-100">{{ $item['warehouse'] ?? '-' }}</td>
<td class="px-2 py-2 mono text-xs text-gray-400 border-r border-gray-100">{{ $item['finished_barcode'] ?? '-' }}</td>
<td class="px-2 py-2 text-xs text-gray-400 border-r border-gray-100">{{ $item['finished_name'] ?? '-' }}</td>
<td class="px-2 py-2 text-xs text-gray-400 border-r border-gray-100">{{ $item['finished_supplier'] ?? '-' }}</td>
{{-- 时间 --}}
<td class="px-2 py-2 text-xs border-r border-gray-100">{{ $item['ship_time'] ?? '-' }}</td>
<td class="px-2 py-2 text-xs text-gray-400 border-r border-gray-100">{{ $item['download_time'] ?? '-' }}</td>
<td class="px-2 py-2 text-xs text-gray-400 border-r border-gray-100">{{ $item['pay_time'] ?? '-' }}</td>
{{-- 备注 --}}
<td class="px-2 py-2 text-xs text-gray-400 border-r border-gray-100 max-w-[130px] truncate" title="{{ $item['buyer_msg'] ?? '' }}">
{{ $item['buyer_msg'] ?? '-' }}
</td>
<td class="px-2 py-2 text-xs text-gray-400 max-w-[130px] truncate" title="{{ $item['seller_memo'] ?? '' }}">
{{ $item['seller_memo'] ?? '-' }}
</td>
</tr>
@empty
<tr>
<td colspan="46" class="text-center py-16 text-gray-400">
<div class="flex flex-col items-center gap-2">
<svg class="w-10 h-10" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<span class="text-sm">暂无运费对账数据</span>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<!-- Pagination -->
@if (isset($freightReconciliations) && $freightReconciliations->hasPages())
<div class="px-4 py-3 border-t border-gray-200 flex items-center justify-between">
<div class="text-sm text-gray-500">
共 <span class="font-medium text-gray-700">{{ $freightReconciliations->total() }}</span> 条记录
</div>
<div class="flex items-center gap-1">
@if ($freightReconciliations->onFirstPage())
<span class="px-3 py-1 text-sm text-gray-300 border border-gray-200 rounded cursor-not-allowed">上一页</span>
@else
<a href="{{ $freightReconciliations->previousPageUrl() }}" class="px-3 py-1 text-sm text-gray-600 border border-gray-200 rounded hover:bg-gray-50 transition">上一页</a>
@endif
@php
$current = $freightReconciliations->currentPage();
$last = $freightReconciliations->lastPage();
$start = max(1, $current - 2);
$end = min($last, $current + 2);
@endphp
@if ($start > 1)
<a href="{{ $freightReconciliations->url(1) }}" class="px-3 py-1 text-sm text-gray-600 border border-gray-200 rounded hover:bg-gray-50 transition">1</a>
@if ($start > 2)
<span class="px-1 text-gray-400">...</span>
@endif
@endif
@for ($p = $start; $p <= $end; $p++)
@if ($p === $current)
<span class="px-3 py-1 text-sm text-white bg-blue-500 border border-blue-500 rounded">{{ $p }}</span>
@else
<a href="{{ $freightReconciliations->url($p) }}" class="px-3 py-1 text-sm text-gray-600 border border-gray-200 rounded hover:bg-gray-50 transition">{{ $p }}</a>
@endif
@endfor
@if ($end < $last)
@if ($end < $last - 1)
<span class="px-1 text-gray-400">...</span>
@endif
<a href="{{ $freightReconciliations->url($last) }}" class="px-3 py-1 text-sm text-gray-600 border border-gray-200 rounded hover:bg-gray-50 transition">{{ $last }}</a>
@endif
@if ($freightReconciliations->hasMorePages())
<a href="{{ $freightReconciliations->nextPageUrl() }}" class="px-3 py-1 text-sm text-gray-600 border border-gray-200 rounded hover:bg-gray-50 transition">下一页</a>
@else
<span class="px-3 py-1 text-sm text-gray-300 border border-gray-200 rounded cursor-not-allowed">下一页</span>
@endif
</div>
</div>
@endif
</div>
</div>
<style>
.mono { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 11px; }
.platform-tag { white-space: nowrap; }
/* Sticky first column on horizontal scroll */
@media (max-width: 768px) {
.overflow-x-auto table { font-size: 10px; }
}
</style>

View File

@ -0,0 +1,19 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '其他扣款补款',
'filters' => [
['name' => 'project', 'label' => '项目', 'placeholder' => '输入项目名称'],
['name' => 'carrier', 'label' => '承运商', 'placeholder' => '输入承运商'],
['name' => 'date_from', 'label' => '日期从', 'type' => 'date'],
['name' => 'date_to', 'label' => '日期至', 'type' => 'date'],
],
'columns' => [
['key' => 'project', 'label' => '项目'],
['key' => 'adjusted_at', 'label' => '日期'],
['key' => 'carrier', 'label' => '承运商'],
['key' => 'amount', 'label' => '补款金额'],
['key' => 'reason', 'label' => '补款原因'],
['key' => 'remark', 'label' => '备注'],
['key' => 'remark_2', 'label' => '备注2'],
],
'emptyText' => '暂无其他扣款补款明细',
])

View File

@ -0,0 +1,342 @@
@php
$records = $records ?? [];
$filters = $filters ?? [];
$groups = $groups ?? [];
$columns = $columns ?? [];
$showIndex = $showIndex ?? true;
$hasGroups = count($groups) > 0;
$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;
}
.courier-subpage {
--courier-border: #e5e7eb;
--courier-muted: #6b7280;
--courier-ink: #1f2937;
--courier-accent: #2563eb;
}
.courier-subpage .page-heading {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 1rem;
margin: 1.5rem 0 1.25rem;
}
.courier-subpage .page-heading h1 {
margin: 0;
color: var(--courier-ink);
font-size: 1.25rem;
font-weight: 700;
}
.courier-subpage .page-heading p {
margin: 0.35rem 0 0;
color: var(--courier-muted);
font-size: 0.8125rem;
}
.courier-subpage .filter-panel,
.courier-subpage .table-panel {
border: 1px solid var(--courier-border);
border-radius: 0.75rem;
background: #ffffff;
box-shadow: 0 4px 14px rgba(31, 41, 55, 0.04);
}
.courier-subpage .filter-panel {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 0.75rem 1rem;
padding: 1rem 1.125rem;
}
.courier-subpage .filter-field {
display: flex;
min-width: 9rem;
flex-direction: column;
gap: 0.3rem;
}
.courier-subpage .filter-field label {
color: var(--courier-muted);
font-size: 0.75rem;
}
.courier-subpage .filter-field input,
.courier-subpage .filter-field select {
min-height: 2.25rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
background: #ffffff;
padding: 0.35rem 0.65rem;
color: var(--courier-ink);
font-size: 0.8125rem;
outline: none;
}
.courier-subpage .filter-field input:focus,
.courier-subpage .filter-field select:focus {
border-color: var(--courier-accent);
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.12);
}
.courier-subpage .filter-actions {
display: flex;
align-items: center;
gap: 0.5rem;
}
.courier-subpage .filter-actions button,
.courier-subpage .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;
transition: background-color 150ms ease, border-color 150ms ease;
}
.courier-subpage .filter-actions button {
border: 1px solid var(--courier-accent);
background: var(--courier-accent);
color: #ffffff;
}
.courier-subpage .filter-actions button:hover {
background: #1d4ed8;
}
.courier-subpage .filter-actions a {
border: 1px solid #d1d5db;
color: #4b5563;
}
.courier-subpage .filter-actions a:hover {
border-color: #9ca3af;
background: #f9fafb;
}
.courier-subpage .table-panel {
margin-top: 1.25rem;
overflow: hidden;
}
.courier-subpage .table-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
border-bottom: 1px solid var(--courier-border);
padding: 0.8rem 1rem;
}
.courier-subpage .table-toolbar strong {
color: var(--courier-ink);
font-size: 0.875rem;
}
.courier-subpage .table-toolbar span {
color: var(--courier-muted);
font-size: 0.75rem;
}
.courier-subpage .table-scroll {
overflow-x: auto;
}
.courier-subpage table {
width: max-content;
min-width: 100%;
border-collapse: collapse;
color: var(--courier-ink);
font-size: 0.75rem;
white-space: nowrap;
}
.courier-subpage th,
.courier-subpage td {
border-right: 1px solid #eef0f3;
border-bottom: 1px solid #eef0f3;
padding: 0.6rem 0.7rem;
text-align: left;
}
.courier-subpage th:last-child,
.courier-subpage td:last-child {
border-right: 0;
}
.courier-subpage thead tr:first-child th {
border-bottom-color: #d1d5db;
background: #f3f4f6;
color: #374151;
font-weight: 700;
text-align: center;
}
.courier-subpage thead tr:last-child th,
.courier-subpage thead tr:first-child th[rowspan="2"] {
background: #f9fafb;
color: #4b5563;
font-weight: 600;
}
.courier-subpage tbody tr:hover {
background: #eff6ff;
}
.courier-subpage .index-column {
position: sticky;
left: 0;
z-index: 1;
min-width: 3.25rem;
background: #ffffff;
text-align: center;
}
.courier-subpage thead .index-column {
background: #f9fafb;
}
.courier-subpage tbody tr:hover .index-column {
background: #eff6ff;
}
.courier-subpage .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;
}
.courier-subpage .page-heading {
align-items: flex-start;
flex-direction: column;
}
.courier-subpage .filter-field {
min-width: min(100%, 13rem);
flex: 1 1 13rem;
}
}
</style>
<div class="courier-subpage">
<div class="page-heading">
<div>
<h1>{{ $title }}</h1>
@if (! empty($subtitle))
<p>{{ $subtitle }}</p>
@endif
</div>
</div>
<form method="GET" class="filter-panel" aria-label="{{ $title }}筛选">
@foreach ($filters as $filter)
<div class="filter-field">
<label for="courier-filter-{{ $filter['name'] }}">{{ $filter['label'] }}</label>
@if (($filter['type'] ?? 'text') === 'select')
<select id="courier-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="courier-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>
@if ($hasGroups)
<tr>
@if ($showIndex)
<th class="index-column" rowspan="2">序号</th>
@endif
@foreach ($groups as $group)
<th colspan="{{ $group['span'] }}">{{ $group['label'] }}</th>
@endforeach
</tr>
<tr>
@foreach ($columns as $column)
<th>{{ $column['label'] }}</th>
@endforeach
</tr>
@else
<tr>
@if ($showIndex)
<th class="index-column">序号</th>
@endif
@foreach ($columns as $column)
<th>{{ $column['label'] }}</th>
@endforeach
</tr>
@endif
</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>

View File

@ -0,0 +1,28 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '素板应付表',
'showIndex' => false,
'filters' => [
['name' => 'month', 'label' => '月份', 'type' => 'month'],
['name' => 'raw_board_factory', 'label' => '素板厂', 'placeholder' => '输入素板厂'],
],
'columns' => [
['key' => 'raw_board_factory', 'label' => '素板厂'],
['key' => 'opening_balance', 'label' => '期初余额'],
['key' => 'june_payment_amount', 'label' => '6月打款金额'],
['key' => 'refund', 'label' => '回款'],
['key' => 'zhiyu_temporary_warehouse', 'label' => '志宇临时仓'],
['key' => 'haoyuan', 'label' => '浩远'],
['key' => 'xinjie', 'label' => '信杰'],
['key' => 'jinyu', 'label' => '金舆'],
['key' => 'suyang', 'label' => '苏阳'],
['key' => 'yongcheng_haohui', 'label' => '永成皓辉'],
['key' => 'tongsheng_lamination_factory', 'label' => '桐盛压贴厂'],
['key' => 'caoxian_songda', 'label' => '曹县松达'],
['key' => 'xusen', 'label' => '旭森'],
['key' => 'compensation', 'label' => '赔付'],
['key' => 'cuiqiao_temporary_warehouse', 'label' => '崔桥临时仓'],
['key' => 'invoice_points', 'label' => '票点'],
['key' => 'june_balance_due', 'label' => '6月欠款'],
],
'emptyText' => '暂无素板应付汇总数据',
])

View File

@ -0,0 +1,21 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '素板价格',
'showIndex' => false,
'filters' => [
['name' => 'price_type', 'label' => '价格类型', 'type' => 'select', 'options' => ['' => '全部']],
['name' => 'material_name', 'label' => '原料名称', 'placeholder' => '输入原料名称'],
['name' => 'material_no', 'label' => '原料编号', 'placeholder' => '输入原料编号'],
['name' => 'target_vendor', 'label' => '目标厂商', 'placeholder' => '输入目标厂商'],
['name' => 'vendor_type', 'label' => '厂商类型', 'type' => 'select', 'options' => ['' => '全部']],
],
'columns' => [
['key' => 'price_type', 'label' => '价格类型'],
['key' => 'material_name', 'label' => '原料名称'],
['key' => 'material_no', 'label' => '原料编号'],
['key' => 'production_no', 'label' => '生产编号'],
['key' => 'latest_price', 'label' => '最新价格'],
['key' => 'target_vendor', 'label' => '目标厂商'],
['key' => 'vendor_type', 'label' => '厂商类型'],
],
'emptyText' => '暂无素板价格数据',
])

View File

@ -0,0 +1,36 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '素板对账',
'showIndex' => false,
'filters' => [
['name' => 'production_no', 'label' => '原料生产编号', 'placeholder' => '输入生产编号'],
['name' => 'material_name', 'label' => '原料名称', 'placeholder' => '输入原料名称'],
['name' => 'outbound_vendor', 'label' => '出库厂商', 'placeholder' => '输入出库厂商'],
['name' => 'arrival_vendor', 'label' => '到货厂商', 'placeholder' => '输入到货厂商'],
['name' => 'stock_in_from', 'label' => '入库日期从', 'type' => 'date'],
['name' => 'stock_in_to', 'label' => '入库日期至', 'type' => 'date'],
],
'columns' => [
['key' => 'stocked_in_at', 'label' => '入库日期'],
['key' => 'stocked_out_at', 'label' => '出库日期'],
['key' => 'production_no', 'label' => '原料生产编号'],
['key' => 'material_name', 'label' => '原料名称'],
['key' => 'outbound_quantity', 'label' => '出库数量'],
['key' => 'unit', 'label' => '单位'],
['key' => 'return_flag', 'label' => '退货标识'],
['key' => 'outbound_vendor', 'label' => '出库厂商'],
['key' => 'arrival_vendor', 'label' => '到货厂商'],
['key' => 'batch_date', 'label' => '批次日期'],
['key' => 'outbound_no', 'label' => '出库单号'],
['key' => 'outbound_remark', 'label' => '出库备注'],
['key' => 'requisition_no', 'label' => '申领单号'],
['key' => 'number_type', 'label' => '单号类型'],
['key' => 'delivery_no', 'label' => '送货单号'],
['key' => 'received_quantity', 'label' => '实收数量'],
['key' => 'unit_price', 'label' => '单价'],
['key' => 'reconciliation_amount', 'label' => '对账金额'],
['key' => 'freight_with_allocation', 'label' => '运费(包含分摊运费)'],
['key' => 'allocated_freight', 'label' => '分摊运费'],
['key' => 'freight', 'label' => '运费'],
],
'emptyText' => '暂无素板对账数据',
])

View File

@ -0,0 +1,18 @@
@include('business.pages.courier-payables.partials.data-table', [
'title' => $page['title'] ?? '赔付明细',
'showIndex' => true,
'filters' => [
['name' => 'lamination_factory', 'label' => '压贴厂', 'placeholder' => '输入压贴厂'],
['name' => 'raw_board_factory', 'label' => '素板厂', 'placeholder' => '输入素板厂'],
['name' => 'reason', 'label' => '原因', 'placeholder' => '输入赔付原因'],
],
'columns' => [
['key' => 'lamination_factory', 'label' => '压贴厂'],
['key' => 'raw_board_factory', 'label' => '素板厂'],
['key' => 'reason', 'label' => '原因'],
['key' => 'quantity', 'label' => '数量'],
['key' => 'unit_price', 'label' => '单价'],
['key' => 'amount', 'label' => '金额'],
],
'emptyText' => '暂无素板赔付明细',
])

View File

@ -0,0 +1,447 @@
<style>
#main-body > .container {
max-width: none;
width: auto;
margin-left: 1.5rem;
margin-right: 1.5rem;
}
.product-prices-filter-bar {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 1rem;
padding: 1.25rem 1.5rem;
border: 1px solid #e5e7eb;
border-radius: 0.75rem;
background: #ffffff;
box-shadow: 0 4px 12px rgba(31, 41, 55, 0.04);
margin-bottom: 1.25rem;
}
.product-prices-filter-bar .filter-group {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.product-prices-filter-bar .filter-label {
font-size: 0.8rem;
font-weight: 600;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.025em;
}
.product-prices-filter-bar input,
.product-prices-filter-bar select {
height: 2.5rem;
padding: 0 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.5rem;
font-size: 0.875rem;
color: #1f2937;
background: #f9fafb;
transition: border-color 150ms, box-shadow 150ms;
min-width: 10rem;
}
.product-prices-filter-bar input:focus,
.product-prices-filter-bar select:focus {
outline: none;
border-color: #4f46e5;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
background: #ffffff;
}
.btn-filter {
display: inline-flex;
align-items: center;
gap: 0.4rem;
height: 2.5rem;
padding: 0 1.25rem;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 600;
border: none;
cursor: pointer;
transition: background 150ms;
}
.btn-filter-primary {
background: #4f46e5;
color: #ffffff;
}
.btn-filter-primary:hover {
background: #4338ca;
}
.btn-filter-secondary {
background: #f3f4f6;
color: #374151;
}
.btn-filter-secondary:hover {
background: #e5e7eb;
}
.price-tag {
display: inline-block;
padding: 0.15rem 0.65rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 600;
line-height: 1.5;
}
.price-tag.dingjia {
background: #e0e7ff;
color: #3730a3;
}
.price-tag.bianjia {
background: #fef3c7;
color: #92400e;
}
.price-diff-positive {
color: #16a34a;
font-weight: 600;
}
.price-diff-negative {
color: #dc2626;
font-weight: 600;
}
.price-diff-zero {
color: #9ca3af;
}
.data-table-wrapper {
border: 1px solid #e5e7eb;
border-radius: 0.75rem;
background: #ffffff;
overflow: hidden;
box-shadow: 0 4px 12px rgba(31, 41, 55, 0.04);
}
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
.data-table thead {
background: #f9fafb;
border-bottom: 2px solid #e5e7eb;
}
.data-table thead th {
padding: 0.85rem 1rem;
text-align: left;
font-weight: 700;
color: #374151;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.025em;
white-space: nowrap;
}
.data-table thead th.right {
text-align: right;
}
.data-table tbody tr {
border-bottom: 1px solid #f3f4f6;
transition: background 120ms;
}
.data-table tbody tr:hover {
background: #f9fafb;
}
.data-table tbody td {
padding: 0.75rem 1rem;
color: #4b5563;
vertical-align: middle;
}
.data-table tbody td.right {
text-align: right;
font-variant-numeric: tabular-nums;
}
.data-table tbody td.mono {
font-family: 'SF Mono', 'Cascadia Code', 'Consolas', monospace;
font-size: 0.8rem;
color: #1f2937;
}
.summary-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.85rem 1.5rem;
background: #f9fafb;
border-top: 1px solid #e5e7eb;
font-size: 0.85rem;
color: #6b7280;
}
.summary-bar strong {
color: #1f2937;
}
.pagination-wrapper {
padding: 1rem 1.5rem;
display: flex;
justify-content: center;
}
.pagination-btn {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2.25rem;
height: 2.25rem;
padding: 0 0.6rem;
border: 1px solid #d1d5db;
border-radius: 0.4rem;
font-size: 0.85rem;
color: #374151;
background: #ffffff;
cursor: pointer;
transition: all 120ms;
}
.pagination-btn:hover {
border-color: #4f46e5;
color: #4f46e5;
}
.pagination-btn.active {
background: #4f46e5;
border-color: #4f46e5;
color: #ffffff;
}
</style>
<div class="my-6">
{{-- Page header --}}
<div class="flex items-center justify-between mb-5">
<div>
<h1 class="text-xl font-bold text-gray-900">
{{ $page['title'] ?? '商品价格' }}
</h1>
<p class="text-sm text-gray-500 mt-1">
管理供应商商品的定价与变价记录
</p>
</div>
<div class="flex items-center gap-3">
<button class="btn-filter btn-filter-secondary">
<span class="material-icons-outlined text-base">file_download</span>
导出
</button>
</div>
</div>
{{-- Filter bar --}}
<form method="GET" class="product-prices-filter-bar">
<div class="filter-group">
<label class="filter-label">条形码</label>
<input type="text" name="barcode" placeholder="输入条形码搜索..."
value="{{ request('barcode') }}">
</div>
<div class="filter-group">
<label class="filter-label">价格类型</label>
<select name="price_type">
<option value="">全部</option>
<option value="0" {{ request('price_type') === '0' ? 'selected' : '' }}>定价</option>
<option value="1" {{ request('price_type') === '1' ? 'selected' : '' }}>变价</option>
</select>
</div>
<div class="filter-group">
<label class="filter-label">是否采购降本</label>
<select name="cost_reduction">
<option value="">全部</option>
<option value="1" {{ request('cost_reduction') === '1' ? 'selected' : '' }}>是</option>
<option value="0" {{ request('cost_reduction') === '0' ? 'selected' : '' }}>否</option>
</select>
</div>
<div class="filter-group">
<label class="filter-label">生效日期起</label>
<input type="date" name="effective_from" value="{{ request('effective_from') }}">
</div>
<div class="filter-group">
<label class="filter-label">生效日期止</label>
<input type="date" name="effective_to" value="{{ request('effective_to') }}">
</div>
<div class="filter-group">
<label class="filter-label">&nbsp;</label>
<div class="flex gap-2">
<button type="submit" class="btn-filter btn-filter-primary">
<span class="material-icons-outlined text-base">search</span>
查询
</button>
<a href="{{ route('business.pages.show', ['company_id' => company_id(), 'section' => $section['slug'], 'page' => $page['slug']]) }}"
class="btn-filter btn-filter-secondary">
<span class="material-icons-outlined text-base">refresh</span>
重置
</a>
</div>
</div>
</form>
{{-- Data table --}}
<div class="data-table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>#</th>
<th>条形码</th>
<th>价格类型</th>
<th>变价类型</th>
<th>是否采购降本</th>
<th class="right">变价前价格</th>
<th class="right">变价后价格</th>
<th class="right">差价</th>
<th>申请人</th>
<th>备注</th>
<th>生效开始时间</th>
<th>生效结束时间</th>
<th>流程完成时间</th>
</tr>
</thead>
<tbody>
@forelse ($productPrices ?? [] as $index => $item)
@php
$priceTypeLabel = ($item->price_type ?? '') === '1' ? '变价' : '定价';
@endphp
<tr>
<td class="mono">{{ ($productPrices->currentPage() - 1) * $productPrices->perPage() + $index + 1 }}</td>
<td class="mono">{{ $item->barcode ?? '-' }}</td>
<td>
<span class="price-tag {{ $priceTypeLabel === '变价' ? 'bianjia' : 'dingjia' }}">
{{ $priceTypeLabel }}
</span>
</td>
<td>{{ $item->change_type ?? '-' }}</td>
<td>
@if (($item->cost_reduction ?? '') === '1')
<span class="material-icons-outlined text-green-600 text-lg">check_circle</span>
@elseif (($item->cost_reduction ?? '') === '0')
<span class="material-icons-outlined text-red-400 text-lg">cancel</span>
@else
<span class="text-gray-300">-</span>
@endif
</td>
<td class="right">{{ isset($item->price_before) && $item->price_before !== null ? number_format((float) $item->price_before, 2) : '-' }}</td>
<td class="right">{{ isset($item->price_after) && $item->price_after !== null ? number_format((float) $item->price_after, 2) : '-' }}</td>
<td class="right">
@php
$diff = $item->price_diff ?? null;
@endphp
@if (isset($diff))
<span class="{{ $diff > 0 ? 'price-diff-positive' : ($diff < 0 ? 'price-diff-negative' : 'price-diff-zero') }}">
{{ $diff > 0 ? '+' : '' }}{{ number_format((float) $diff, 2) }}
</span>
@else
-
@endif
</td>
<td>{{ $item->applicant ?? '-' }}</td>
<td>
@if (!empty($item->remark))
<span title="{{ $item->remark }}">
{{ mb_strlen($item->remark) > 12 ? mb_substr($item->remark, 0, 12) . '...' : $item->remark }}
</span>
@else
-
@endif
</td>
<td>{{ $item->effective_start ?? '-' }}</td>
<td>{{ $item->effective_end ?? '-' }}</td>
<td>{{ $item->completed_at ?? '-' }}</td>
</tr>
@empty
<tr>
<td colspan="13" class="text-center py-12 text-gray-400">
<span class="material-icons-outlined text-4xl mb-2 block">inventory_2</span>
暂无商品价格数据
</td>
</tr>
@endforelse
</tbody>
</table>
{{-- Summary bar --}}
@if (!empty($productPrices) && method_exists($productPrices, 'total'))
<div class="summary-bar">
<span>
共 <strong>{{ $productPrices->total() }}</strong> 条记录
</span>
<span>
当前第 <strong>{{ $productPrices->currentPage() }}</strong> / <strong>{{ $productPrices->lastPage() }}</strong> 页
</span>
</div>
{{-- Pagination --}}
@if (isset($productPrices) && $productPrices->hasPages())
<div class="pagination-wrapper">
<div class="flex items-center gap-1.5">
{{-- Previous --}}
@if ($productPrices->onFirstPage())
<span class="pagination-btn opacity-40 cursor-not-allowed">
<span class="material-icons-outlined text-sm">chevron_left</span>
</span>
@else
<a href="{{ $productPrices->previousPageUrl() }}" class="pagination-btn">
<span class="material-icons-outlined text-sm">chevron_left</span>
</a>
@endif
{{-- Page numbers --}}
@php
$current = $productPrices->currentPage();
$last = $productPrices->lastPage();
$start = max(1, $current - 2);
$end = min($last, $current + 2);
@endphp
@if ($start > 1)
<a href="{{ $productPrices->url(1) }}" class="pagination-btn">1</a>
@if ($start > 2)
<span class="pagination-btn opacity-50 cursor-default">...</span>
@endif
@endif
@for ($i = $start; $i <= $end; $i++)
<a href="{{ $productPrices->url($i) }}" class="pagination-btn {{ $i === $current ? 'active' : '' }}">
{{ $i }}
</a>
@endfor
@if ($end < $last)
@if ($end < $last - 1)
<span class="pagination-btn opacity-50 cursor-default">...</span>
@endif
<a href="{{ $productPrices->url($last) }}" class="pagination-btn">{{ $last }}</a>
@endif
{{-- Next --}}
@if ($productPrices->hasMorePages())
<a href="{{ $productPrices->nextPageUrl() }}" class="pagination-btn">
<span class="material-icons-outlined text-sm">chevron_right</span>
</a>
@else
<span class="pagination-btn opacity-40 cursor-not-allowed">
<span class="material-icons-outlined text-sm">chevron_right</span>
</span>
@endif
</div>
</div>
@endif
@endif
</div>
</div>