:<页面>),初始为空,由页面上的导入、导出、查询、编辑维护。 */ class PayablesFinalActions extends Controller { public const DATASET_PREFIX = 'final:'; public function __construct( private readonly PayablesFinalRegistry $registry, private readonly SupplierPayableImportTemplate $template, private readonly SupplierPayableOverrideStore $overrides, private readonly PayablesFinalImporter $importer, private readonly PayablesFieldNormalizer $normalizer, ) { $this->middleware('auth'); $this->middleware('company.identify'); } public function definition(Request $request): JsonResponse { return response()->json([ 'dataset' => $this->dataset($request), 'fields' => collect($this->fields($request)) ->map(static fn (array $definition, string $name): array => ['name' => $name] + $definition) ->values() ->all(), ]); } public function template(Request $request): StreamedResponse { return $this->template->download( $this->registry->title($this->section($request), $this->dataset($request)), $this->fields($request), true, ); } public function import(Request $request): JsonResponse|RedirectResponse { $request->validate(['import' => ['required', 'file', 'mimes:xlsx,xls,csv', 'max:10240']]); $result = $this->importer->import( $this->fields($request), $this->storeDataset($request), $request->file('import'), (int) (company_id() ?: 1), user_id() ? (int) user_id() : null, ); $message = "导入完成:新增 {$result['created']} 条,更新 {$result['updated']} 条。"; return $request->expectsJson() ? response()->json(['message' => $message] + $result) : back()->with('success', $message); } public function update(Request $request, string $recordKey): JsonResponse|RedirectResponse { $values = $this->normalizer->normalize($this->fields($request), (array) $request->input('values', [])); $result = $this->overrides->save( $this->storeDataset($request), $recordKey, $values, (int) (company_id() ?: 1), user_id() ? (int) user_id() : null, ); return $request->expectsJson() ? response()->json(['message' => '保存成功。'] + $result) : back()->with('success', '保存成功。'); } public function export(Request $request): StreamedResponse { $fields = $this->fields($request); $title = $this->registry->title($this->section($request), $this->dataset($request)); $rows = $this->overrides->listRows($this->storeDataset($request), (int) (company_id() ?: 1)); return response()->streamDownload(function () use ($rows, $fields): void { $csv = fopen('php://output', 'w'); if ($csv === false) { throw new RuntimeException('无法创建导出文件。'); } fputs($csv, chr(0xEF) . chr(0xBB) . chr(0xBF)); fputcsv($csv, array_merge(['记录标识'], array_column($fields, 'label'))); foreach ($rows as $row) { $values = [$this->csvText($row['_action_key'] ?? '')]; foreach ($fields as $field => $definition) { $value = $row[$field] ?? ''; $values[] = $definition['type'] === 'number' && is_numeric($value) ? $value : $this->csvText($value); } fputcsv($csv, $values); } fclose($csv); }, $title . '_' . now()->format('Ymd_His') . '.csv', [ 'Content-Type' => 'text/csv; charset=UTF-8', 'Cache-Control' => 'private, no-store', ]); } private function section(Request $request): string { return (string) $request->route('finalSection'); } private function dataset(Request $request): string { $dataset = (string) $request->route('dataset'); $this->registry->title($this->section($request), $dataset); return $dataset; } /** @return array */ private function fields(Request $request): array { return $this->registry->fields($this->section($request), $this->dataset($request)); } private function storeDataset(Request $request): string { $section = $this->section($request) === PayablesFinalRegistry::SECTION_COURIER ? 'courier' : 'supplier'; return self::DATASET_PREFIX . $section . ':' . $this->dataset($request); } private function csvText(mixed $value): string { $value = (string) $value; return preg_match('/^[=+\-@\t\r]/u', $value) === 1 ? "\t" . $value : $value; } }