商品推广费用当前页导出 #70
@ -44,6 +44,20 @@
|
||||
<span class="material-icons-outlined" aria-hidden="true">refresh</span>
|
||||
<span>重置</span>
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
id="order-data-promotion-export-button"
|
||||
data-export-contract="order-data.promotion.current-page-export"
|
||||
data-export-table="order-data-promotion-table"
|
||||
data-export-filename="商品推广费用明细_{{ $filters['date'] ?? '日期' }}_第{{ $rows?->currentPage() ?? 1 }}页.csv"
|
||||
@class(['upstream-data-button', 'is-disabled' => !$rows || $rows->isEmpty()])
|
||||
@if (!$rows || $rows->isEmpty()) disabled="disabled" aria-disabled="true" @endif
|
||||
aria-label="导出当前页"
|
||||
title="导出当前页"
|
||||
>
|
||||
<span class="material-icons-outlined" aria-hidden="true">download</span>
|
||||
<span>导出当前页</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -56,7 +70,7 @@
|
||||
|
||||
<div class="upstream-data-table-panel">
|
||||
<div class="upstream-data-table-scroll">
|
||||
<table class="upstream-data-table order-data-table" aria-label="商品推广费用明细">
|
||||
<table id="order-data-promotion-table" class="upstream-data-table order-data-table" aria-label="商品推广费用明细">
|
||||
<thead>
|
||||
<tr>
|
||||
@foreach ($columns as $field => $header)
|
||||
@ -69,7 +83,11 @@
|
||||
<tr>
|
||||
@foreach ($columns as $field => $header)
|
||||
@php $value = data_get($row, $field); @endphp
|
||||
<td @class(['is-number' => $field === 'promotion_fee'])>
|
||||
<td
|
||||
data-export-value="{{ $value ?? '' }}"
|
||||
data-export-number="{{ $field === 'promotion_fee' ? 'true' : 'false' }}"
|
||||
@class(['is-number' => $field === 'promotion_fee'])
|
||||
>
|
||||
@if ($field === 'promotion_fee')
|
||||
{{ $value === null || $value === '' ? '-' : number_format((float) $value, 2) }}
|
||||
@else
|
||||
@ -109,3 +127,51 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(() => {
|
||||
const button = document.getElementById('order-data-promotion-export-button');
|
||||
|
||||
if (!button || button.dataset.exportBound === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
button.dataset.exportBound = 'true';
|
||||
button.addEventListener('click', () => {
|
||||
const table = document.getElementById(button.dataset.exportTable || '');
|
||||
const bodyRows = table ? Array.from(table.querySelectorAll('tbody tr:not(.is-empty)')) : [];
|
||||
|
||||
if (!table || bodyRows.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const protectSpreadsheetFormula = (value) => /^[=+\-@\t\r]/.test(value) ? `'${value}` : value;
|
||||
const csvCell = (value, isNumber = false) => {
|
||||
const raw = String(value ?? '').replace(/\r\n?/g, '\n');
|
||||
const normalized = isNumber ? raw : protectSpreadsheetFormula(raw);
|
||||
|
||||
return `"${normalized.replace(/"/g, '""')}"`;
|
||||
};
|
||||
const header = Array.from(table.querySelectorAll('thead th'))
|
||||
.map((cell) => csvCell(cell.textContent.trim()));
|
||||
const rows = bodyRows.map((row) => Array.from(row.querySelectorAll('td'))
|
||||
.map((cell) => csvCell(
|
||||
cell.dataset.exportValue ?? cell.textContent.trim(),
|
||||
cell.dataset.exportNumber === 'true',
|
||||
)));
|
||||
const csv = [header, ...rows].map((row) => row.join(',')).join('\r\n');
|
||||
const blob = new Blob(['\uFEFF', csv], { type: 'text/csv;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
|
||||
link.href = url;
|
||||
link.download = button.dataset.exportFilename || '商品推广费用明细.csv';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
window.setTimeout(() => {
|
||||
link.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
}, 1000);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
@ -33,7 +33,7 @@ class OrderDataPagesUpstreamTest extends FeatureTestCase
|
||||
'date' => '2026-08-09',
|
||||
'rows' => [[
|
||||
'shop_name' => '推广测试店铺',
|
||||
'product_code' => 'SKU-1',
|
||||
'product_code' => '=SKU-1',
|
||||
'promotion_fee' => 9.05,
|
||||
]],
|
||||
];
|
||||
@ -73,16 +73,27 @@ class OrderDataPagesUpstreamTest extends FeatureTestCase
|
||||
->assertSee('URL.revokeObjectURL(url);', false)
|
||||
->assertSee('订单售后费用明细_2026-08-01_2026-08-09_第1页.csv', false);
|
||||
|
||||
$this->get(route('business.pages.show', [
|
||||
$promotionResponse = $this->get(route('business.pages.show', [
|
||||
'section' => 'order-data',
|
||||
'page' => 'raw-data',
|
||||
'tab' => 'promotion-expenses',
|
||||
]))
|
||||
]));
|
||||
|
||||
$promotionResponse
|
||||
->assertOk()
|
||||
->assertSeeText('推广测试店铺')
|
||||
->assertSeeText('SKU-1')
|
||||
->assertSeeText('9.05')
|
||||
->assertSee('value="2026-08-09"', false);
|
||||
->assertSee('value="2026-08-09"', false)
|
||||
->assertSee('id="order-data-promotion-export-button"', false)
|
||||
->assertSee('data-export-contract="order-data.promotion.current-page-export"', false)
|
||||
->assertSee('data-export-table="order-data-promotion-table"', false)
|
||||
->assertSee('data-export-value="=SKU-1"', false)
|
||||
->assertSee('data-export-value="9.05"', false)
|
||||
->assertSee('data-export-number="true"', false)
|
||||
->assertSee('protectSpreadsheetFormula', false)
|
||||
->assertSee('URL.revokeObjectURL(url);', false)
|
||||
->assertSee('商品推广费用明细_2026-08-09_第1页.csv', false);
|
||||
}
|
||||
|
||||
public function test_order_data_page_keeps_rendering_when_the_upstream_is_unavailable(): void
|
||||
@ -104,7 +115,9 @@ class OrderDataPagesUpstreamTest extends FeatureTestCase
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSeeText('首份共享快照正在准备。')
|
||||
->assertSeeText('暂无数据');
|
||||
->assertSeeText('暂无数据')
|
||||
->assertSee('id="order-data-promotion-export-button"', false)
|
||||
->assertSee('disabled="disabled"', false);
|
||||
}
|
||||
|
||||
public function test_after_sales_export_is_disabled_when_the_current_page_has_no_rows(): void
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user