CaiWuXiTong/app/Http/Controllers/Business/CourierPayableSummaries.php

136 lines
4.6 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\BinaryFileResponse;
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 template(string $summaryPage): BinaryFileResponse
{
$this->authorizePage($summaryPage);
abort_unless($summaryPage === 'freight-difference', 404);
$path = resource_path('templates/courier-payables/freight-difference-import-template.xlsx');
abort_unless(is_file($path), 404);
$response = response()->download($path, 'freight_difference_import_template.xlsx', [
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Cache-Control' => 'private, no-store',
]);
return $response->setContentDisposition(
'attachment',
'运费差导入模板.xlsx',
'freight_difference_import_template.xlsx',
);
}
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;
}
}