CaiWuXiTong/app/Http/Controllers/Business/CourierPayableSummaries.php
renshen 57a417de30 新增快递应付运费差和附加费汇总页面 (#200)
新增两个汇总子页面,并提供按公司隔离的导入、展示和导出能力。
2026-09-17 16:18:51 +08:00

115 lines
3.8 KiB
PHP

<?php
namespace App\Http\Controllers\Business;
use App\Business\CourierPayableSummaryStore;
use App\Utilities\SidebarPermissions;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use RuntimeException;
use Symfony\Component\HttpFoundation\StreamedResponse;
class CourierPayableSummaries extends Controller
{
public function __construct(private readonly CourierPayableSummaryStore $store)
{
$this->middleware('auth');
$this->middleware('company.identify');
}
public function import(Request $request, string $summaryPage): RedirectResponse
{
$this->authorizePage($summaryPage);
$this->store->title($summaryPage);
$request->validate([
'import' => ['required', 'file', 'mimes:xlsx,xls,csv', 'max:10240'],
]);
try {
$result = $this->store->import(
$request->file('import'),
(int) (company_id() ?: 1),
$summaryPage,
user_id() ? (int) user_id() : null,
);
} catch (RuntimeException $exception) {
report($exception);
return $this->redirectToPage($summaryPage)->with('error', '汇总数据保存失败,请稍后重试。');
}
return $this->redirectToPage($summaryPage)->with(
'success',
"导入完成:{$result['rows']} 条数据,{$result['columns']} 个字段。",
);
}
public function export(string $summaryPage): StreamedResponse|RedirectResponse
{
$this->authorizePage($summaryPage);
$title = $this->store->title($summaryPage);
try {
$snapshot = $this->store->snapshot((int) (company_id() ?: 1), $summaryPage);
} catch (RuntimeException) {
return $this->redirectToPage($summaryPage)->with('error', '汇总数据暂时无法读取,请重新导入后再试。');
}
if ($snapshot === null) {
return $this->redirectToPage($summaryPage)->with('error', '当前没有可导出的汇总数据。');
}
return response()->streamDownload(function () use ($snapshot): void {
$csv = fopen('php://output', 'w');
if ($csv === false) {
throw new RuntimeException('无法创建汇总数据导出流。');
}
fputs($csv, chr(0xEF) . chr(0xBB) . chr(0xBF));
fputcsv($csv, array_map([$this, 'csvText'], $snapshot['headers']));
foreach ($snapshot['rows'] as $row) {
fputcsv($csv, array_map([$this, 'csvText'], $row));
}
fclose($csv);
}, $title . '_' . now()->format('Ymd_His') . '.csv', [
'Content-Type' => 'text/csv; charset=UTF-8',
'Cache-Control' => 'private, no-store',
]);
}
private function redirectToPage(string $summaryPage): RedirectResponse
{
return redirect()->route('business.pages.show', [
'section' => 'courier-payables',
'page' => $summaryPage,
]);
}
private function authorizePage(string $summaryPage): void
{
$section = collect(SidebarPermissions::navigationFor(user()))
->firstWhere('slug', 'courier-payables');
$pages = collect($section['pages'] ?? [])->flatMap(static fn (array $page): array => [
$page,
...($page['children'] ?? []),
]);
abort_unless($pages->contains('slug', $summaryPage), 403, '当前账号没有该页面权限。');
}
private function csvText(mixed $value): string
{
$value = (string) $value;
if (preg_match('/^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)%?$/u', $value) === 1) {
return $value;
}
return preg_match('/^[=+\-@\t\r]/u', $value) === 1 ? "\t" . $value : $value;
}
}